drm-misc-next for v5.18:
UAPI Changes: - Fix invalid IN_FORMATS blob when plane->format_mod_supported is NULL. Cross-subsystem Changes: - Assorted dt bindings updates. - Fix vga16fb vga checking on x86. - Fix extra semicolon in rwsem.h's _down_write_nest_lock. - Assorted small fixes to agp and fbdev drivers. - Fix oops in creating a udmabuf with 0 pages. - Hot-unplug firmware fb devices on forced removal - Reqquest memory region in simplefb and simpledrm, and don't make the ioresource as busy. Core Changes: - Mock a drm_plane in drm-plane-helper selftest. - Assorted bug fixes to device logging, dbi. - Use DP helper for sink count in mst. - Assorted documentation fixes. - Assorted small fixes. - Move DP headers to drm/dp, and add a drm dp helper module. - Move the buddy allocator from i915 to common drm. - Add simple pci and platform module init macros to remove a lot of boilerplate from some drivers. - Support microsoft extension for HMDs and specialized monitors. - Improve edid parser's deep color handling. - Add type 7 timing support to edid parser. - Add a weak backpointer to the ttm_bo from ttm_resource - Add 3 eDP panels. Driver Changes: - Add support for HDMI and JZ4780 to ingenic. - Add support for higher DP/eDP bitrates to nouveau. - Assorted driver fixes to tilcdc, vmwgfx, sn65dsi83, meson, stm, panfrost, v3d, gma500, vc4, virtio, mgag200, ast, radeon, amdgpu, nouveau, various bridge drivers. - Convert and revert exynos dsi support to bridge driver. - Add vcc supply regulator support for sn65dsi83. - More conversion of bridge/chipone-icn6211 to atomic. - Remove conflicting fb's from stm, and add support for new hw version. - Add device link in parade-ps8640 to fix suspend/resume. - Update Boe-tv110c9m init sequence. - Add wide screen support to AST2600. - Fix omapdrm implicit dma_buf fencing. - Add support for multiple overlay planes to vkms. - Convert bridge/anx7625 to atomic, add HDCP support, add eld support for audio, and fix HPD. - Add driver for ChromeOS privacy screen. - Handover display from firmware to vc4 more gracefully, and support nomodeset. - Add flexible and ycbcr pixel formats to stm/ltdc. - Convert exynos mipi dsi to atomic. - Add initial dual core group GPUs support to panfrost. - No longer add exclusive fence in amdgpu as shared fence. - Add CSC and full range supoprt to vc4. - Shutdown the display on system shutdown and unbind. - Add Multi-Inno Technology MI0700S4T-6 simple panel. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmHyiHMACgkQ/lWMcqZw E8OLfQ//Xd1njt93nRGoQofuQkz23n2AUTAnmbwzQKcvmat8ugXbRJ5JaVQJrFpu OQEYM46eZIyu2LekMiz4HgPK8CjS156QJ1WtltUFglOY1KLejb6HF5boBYxLkIC7 wLhkaRiwed4t7WOTrftgzpH5FNj/7Vi+Hav9l8rYRC74sWanEZNGBJL2OD9GRdlU 3tlmY8oXVAN8YDD/43Cv+foOTzLS/COI7JCFgFRhfzoFss3EVR061u55uOq18STB UI29NusqX7/K6hQAWCKl0EQBEZWMR02/dgu3ZpOEHHAa96RgHxIuRYsIO9kvGgiF VyW0EW6AyD/KsOSBYnsfUqkFfNchx9Xb8ZDjIhHUYxPsxe4iUJneCrdIKEmLWgSd 1bVNrltLJKBQARW4Whpy/gaiKV8RD8YVJobA/+/COeCUXCnNAT43O9aJmix/7253 Q7ORXTss5WRpuYswMWmObebf8p3IhFjTvlzzenXynl7mkaohGzHPf6SUSUZbJ8Df PZCh17McwIEQ1BtYeegeAGM6s8lrv5+yZaY4bnkQsJNOHeab0cPqmQ8/s+hUeRtp 3VDRVhkgzz2XuTaiKia0gWcAQbdZ2KornkP4QMyDH7w0+6bsuJnNXe4L1XY9lt4J 5v411FaD61FbGDhu5PFtYI7+ZlgM0h5sqlhVkUEzbckzTF3SC9c= =IMtm -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2022-01-27' of git://anongit.freedesktop.org/drm/drm-misc into drm-next [airlied: add two missing Kconfig] drm-misc-next for v5.18: UAPI Changes: - Fix invalid IN_FORMATS blob when plane->format_mod_supported is NULL. Cross-subsystem Changes: - Assorted dt bindings updates. - Fix vga16fb vga checking on x86. - Fix extra semicolon in rwsem.h's _down_write_nest_lock. - Assorted small fixes to agp and fbdev drivers. - Fix oops in creating a udmabuf with 0 pages. - Hot-unplug firmware fb devices on forced removal - Reqquest memory region in simplefb and simpledrm, and don't make the ioresource as busy. Core Changes: - Mock a drm_plane in drm-plane-helper selftest. - Assorted bug fixes to device logging, dbi. - Use DP helper for sink count in mst. - Assorted documentation fixes. - Assorted small fixes. - Move DP headers to drm/dp, and add a drm dp helper module. - Move the buddy allocator from i915 to common drm. - Add simple pci and platform module init macros to remove a lot of boilerplate from some drivers. - Support microsoft extension for HMDs and specialized monitors. - Improve edid parser's deep color handling. - Add type 7 timing support to edid parser. - Add a weak backpointer to the ttm_bo from ttm_resource - Add 3 eDP panels. Driver Changes: - Add support for HDMI and JZ4780 to ingenic. - Add support for higher DP/eDP bitrates to nouveau. - Assorted driver fixes to tilcdc, vmwgfx, sn65dsi83, meson, stm, panfrost, v3d, gma500, vc4, virtio, mgag200, ast, radeon, amdgpu, nouveau, various bridge drivers. - Convert and revert exynos dsi support to bridge driver. - Add vcc supply regulator support for sn65dsi83. - More conversion of bridge/chipone-icn6211 to atomic. - Remove conflicting fb's from stm, and add support for new hw version. - Add device link in parade-ps8640 to fix suspend/resume. - Update Boe-tv110c9m init sequence. - Add wide screen support to AST2600. - Fix omapdrm implicit dma_buf fencing. - Add support for multiple overlay planes to vkms. - Convert bridge/anx7625 to atomic, add HDCP support, add eld support for audio, and fix HPD. - Add driver for ChromeOS privacy screen. - Handover display from firmware to vc4 more gracefully, and support nomodeset. - Add flexible and ycbcr pixel formats to stm/ltdc. - Convert exynos mipi dsi to atomic. - Add initial dual core group GPUs support to panfrost. - No longer add exclusive fence in amdgpu as shared fence. - Add CSC and full range supoprt to vc4. - Shutdown the display on system shutdown and unbind. - Add Multi-Inno Technology MI0700S4T-6 simple panel. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/456a23c6-7324-7543-0c45-751f30ef83f7@linux.intel.com
This commit is contained in:
		
						commit
						53dbee4926
					
				| @ -39,6 +39,7 @@ properties: | ||||
|           - const: lvds-encoder # Generic LVDS encoder compatible fallback | ||||
|       - items: | ||||
|           - enum: | ||||
|               - ti,ds90cf364a # For the DS90CF364A FPD-Link LVDS Receiver | ||||
|               - ti,ds90cf384a # For the DS90CF384A FPD-Link LVDS Receiver | ||||
|           - const: lvds-decoder # Generic LVDS decoders compatible fallback | ||||
|       - enum: | ||||
|  | ||||
| @ -32,6 +32,9 @@ properties: | ||||
|     maxItems: 1 | ||||
|     description: GPIO specifier for bridge_en pin (active high). | ||||
| 
 | ||||
|   vcc-supply: | ||||
|     description: A 1.8V power supply (see regulator/regulator.yaml). | ||||
| 
 | ||||
|   ports: | ||||
|     $ref: /schemas/graph.yaml#/properties/ports | ||||
| 
 | ||||
| @ -91,7 +94,6 @@ properties: | ||||
| required: | ||||
|   - compatible | ||||
|   - reg | ||||
|   - enable-gpios | ||||
|   - ports | ||||
| 
 | ||||
| allOf: | ||||
| @ -133,6 +135,7 @@ examples: | ||||
|             reg = <0x2d>; | ||||
| 
 | ||||
|             enable-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; | ||||
|             vcc-supply = <®_sn65dsi83_1v8>; | ||||
| 
 | ||||
|             ports { | ||||
|                 #address-cells = <1>; | ||||
|  | ||||
| @ -222,6 +222,8 @@ properties: | ||||
|       - logictechno,lttd800480070-l6wh-rt | ||||
|         # Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel | ||||
|       - mitsubishi,aa070mc01-ca1 | ||||
|         # Multi-Inno Technology Co.,Ltd MI0700S4T-6 7" 800x480 TFT Resistive Touch Module | ||||
|       - multi-inno,mi0700s4t-6 | ||||
|         # Multi-Inno Technology Co.,Ltd MI1010AIT-1CP 10.1" 1280x800 LVDS IPS Cap Touch Mod. | ||||
|       - multi-inno,mi1010ait-1cp | ||||
|         # NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel | ||||
|  | ||||
| @ -4,7 +4,12 @@ | ||||
| $id: http://devicetree.org/schemas/display/panel/sony,acx424akp.yaml# | ||||
| $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||
| 
 | ||||
| title: Sony ACX424AKP 4" 480x864 AMOLED panel | ||||
| title: Sony ACX424AKP/ACX424AKM 4" 480x864/480x854 AMOLED panel | ||||
| 
 | ||||
| description: The Sony ACX424AKP and ACX424AKM are panels built around | ||||
|   the Novatek NT35560 display controller. The only difference is that | ||||
|   the AKM is configured to use 10 pixels less in the Y axis than the | ||||
|   AKP. | ||||
| 
 | ||||
| maintainers: | ||||
|   - Linus Walleij <linus.walleij@linaro.org> | ||||
| @ -14,7 +19,9 @@ allOf: | ||||
| 
 | ||||
| properties: | ||||
|   compatible: | ||||
|     const: sony,acx424akp | ||||
|     enum: | ||||
|       - sony,acx424akp | ||||
|       - sony,acx424akm | ||||
|   reg: true | ||||
|   reset-gpios: true | ||||
|   vddi-supply: | ||||
|  | ||||
| @ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the | ||||
| kernel log at initialization time and passes it to userspace through the | ||||
| DRM_IOCTL_VERSION ioctl. | ||||
| 
 | ||||
| Module Initialization | ||||
| --------------------- | ||||
| 
 | ||||
| .. kernel-doc:: include/drm/drm_module.h | ||||
|    :doc: overview | ||||
| 
 | ||||
| Managing Ownership of the Framebuffer Aperture | ||||
| ---------------------------------------------- | ||||
| 
 | ||||
|  | ||||
| @ -232,34 +232,34 @@ HDCP Helper Functions Reference | ||||
| Display Port Helper Functions Reference | ||||
| ======================================= | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_dp_helper.c | ||||
| .. kernel-doc:: drivers/gpu/drm/dp/drm_dp.c | ||||
|    :doc: dp helpers | ||||
| 
 | ||||
| .. kernel-doc:: include/drm/drm_dp_helper.h | ||||
| .. kernel-doc:: include/drm/dp/drm_dp_helper.h | ||||
|    :internal: | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_dp_helper.c | ||||
| .. kernel-doc:: drivers/gpu/drm/dp/drm_dp.c | ||||
|    :export: | ||||
| 
 | ||||
| Display Port CEC Helper Functions Reference | ||||
| =========================================== | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c | ||||
| .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_cec.c | ||||
|    :doc: dp cec helpers | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c | ||||
| .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_cec.c | ||||
|    :export: | ||||
| 
 | ||||
| Display Port Dual Mode Adaptor Helper Functions Reference | ||||
| ========================================================= | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c | ||||
| .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_dual_mode_helper.c | ||||
|    :doc: dp dual mode helpers | ||||
| 
 | ||||
| .. kernel-doc:: include/drm/drm_dp_dual_mode_helper.h | ||||
| .. kernel-doc:: include/drm/dp/drm_dp_dual_mode_helper.h | ||||
|    :internal: | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c | ||||
| .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_dual_mode_helper.c | ||||
|    :export: | ||||
| 
 | ||||
| Display Port MST Helpers | ||||
| @ -268,19 +268,19 @@ Display Port MST Helpers | ||||
| Overview | ||||
| -------- | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | ||||
| .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c | ||||
|    :doc: dp mst helper | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | ||||
| .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c | ||||
|    :doc: Branch device and port refcounting | ||||
| 
 | ||||
| Functions Reference | ||||
| ------------------- | ||||
| 
 | ||||
| .. kernel-doc:: include/drm/drm_dp_mst_helper.h | ||||
| .. kernel-doc:: include/drm/dp/drm_dp_mst_helper.h | ||||
|    :internal: | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | ||||
| .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c | ||||
|    :export: | ||||
| 
 | ||||
| Topology Lifetime Internals | ||||
| @ -289,7 +289,7 @@ Topology Lifetime Internals | ||||
| These functions aren't exported to drivers, but are documented here to help make | ||||
| the MST topology helpers easier to understand | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | ||||
| .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c | ||||
|    :functions: drm_dp_mst_topology_try_get_mstb drm_dp_mst_topology_get_mstb | ||||
|                drm_dp_mst_topology_put_mstb | ||||
|                drm_dp_mst_topology_try_get_port drm_dp_mst_topology_get_port | ||||
|  | ||||
| @ -423,12 +423,12 @@ Connector Functions Reference | ||||
| Writeback Connectors | ||||
| -------------------- | ||||
| 
 | ||||
| .. kernel-doc:: include/drm/drm_writeback.h | ||||
|   :internal: | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_writeback.c | ||||
|   :doc: overview | ||||
| 
 | ||||
| .. kernel-doc:: include/drm/drm_writeback.h | ||||
|   :internal: | ||||
| 
 | ||||
| .. kernel-doc:: drivers/gpu/drm/drm_writeback.c | ||||
|   :export: | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ the very dynamic nature of many of that data, managing graphics memory | ||||
| efficiently is thus crucial for the graphics stack and plays a central | ||||
| role in the DRM infrastructure. | ||||
| 
 | ||||
| The DRM core includes two memory managers, namely Translation Table Maps | ||||
| The DRM core includes two memory managers, namely Translation Table Manager | ||||
| (TTM) and Graphics Execution Manager (GEM). TTM was the first DRM memory | ||||
| manager to be developed and tried to be a one-size-fits-them all | ||||
| solution. It provides a single userspace API to accommodate the need of | ||||
|  | ||||
| @ -467,6 +467,21 @@ Contact: Thomas Zimmermann <tzimmermann@suse.de> | ||||
| 
 | ||||
| Level: Intermediate | ||||
| 
 | ||||
| Request memory regions in all drivers | ||||
| ------------------------------------- | ||||
| 
 | ||||
| Go through all drivers and add code to request the memory regions that the | ||||
| driver uses. This requires adding calls to request_mem_region(), | ||||
| pci_request_region() or similar functions. Use helpers for managed cleanup | ||||
| where possible. | ||||
| 
 | ||||
| Drivers are pretty bad at doing this and there used to be conflicts among | ||||
| DRM and fbdev drivers. Still, it's the correct thing to do. | ||||
| 
 | ||||
| Contact: Thomas Zimmermann <tzimmermann@suse.de> | ||||
| 
 | ||||
| Level: Starter | ||||
| 
 | ||||
| 
 | ||||
| Core refactorings | ||||
| ================= | ||||
|  | ||||
| @ -124,8 +124,6 @@ Add Plane Features | ||||
| 
 | ||||
| There's lots of plane features we could add support for: | ||||
| 
 | ||||
| - Multiple overlay planes. [Good to get started] | ||||
| 
 | ||||
| - Clearing primary plane: clear primary plane before plane composition (at the | ||||
|   start) for correctness of pixel blend ops. It also guarantees alpha channel | ||||
|   is cleared in the target buffer for stable crc. [Good to get started] | ||||
|  | ||||
| @ -55,7 +55,7 @@ static struct _ati_generic_private { | ||||
| 
 | ||||
| static int ati_create_page_map(struct ati_page_map *page_map) | ||||
| { | ||||
| 	int i, err = 0; | ||||
| 	int i, err; | ||||
| 
 | ||||
| 	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); | ||||
| 	if (page_map->real == NULL) | ||||
| @ -63,6 +63,10 @@ static int ati_create_page_map(struct ati_page_map *page_map) | ||||
| 
 | ||||
| 	set_memory_uc((unsigned long)page_map->real, 1); | ||||
| 	err = map_page_into_agp(virt_to_page(page_map->real)); | ||||
| 	if (err) { | ||||
| 		free_page((unsigned long)page_map->real); | ||||
| 		return err; | ||||
| 	} | ||||
| 	page_map->remapped = page_map->real; | ||||
| 
 | ||||
| 	for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { | ||||
| @ -303,7 +307,7 @@ static int ati_insert_memory(struct agp_memory * mem, | ||||
| 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { | ||||
| 		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; | ||||
| 		cur_gatt = GET_GATT(addr); | ||||
| 		writel(agp_bridge->driver->mask_memory(agp_bridge,	 | ||||
| 		writel(agp_bridge->driver->mask_memory(agp_bridge, | ||||
| 						       page_to_phys(mem->pages[i]), | ||||
| 						       mem->type), | ||||
| 		       cur_gatt+GET_GATT_OFF(addr)); | ||||
|  | ||||
| @ -62,6 +62,7 @@ EXPORT_SYMBOL(agp_find_bridge); | ||||
| 
 | ||||
| /**
 | ||||
|  *	agp_backend_acquire  -  attempt to acquire an agp backend. | ||||
|  *	@pdev: the PCI device | ||||
|  * | ||||
|  */ | ||||
| struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev) | ||||
| @ -83,6 +84,7 @@ EXPORT_SYMBOL(agp_backend_acquire); | ||||
| 
 | ||||
| /**
 | ||||
|  *	agp_backend_release  -  release the lock on the agp backend. | ||||
|  *	@bridge: the AGP backend to release | ||||
|  * | ||||
|  *	The caller must insure that the graphics aperture translation table | ||||
|  *	is read for use by another entity. | ||||
|  | ||||
| @ -39,7 +39,9 @@ | ||||
| #include <linux/fs.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/uaccess.h> | ||||
| 
 | ||||
| #include "agp.h" | ||||
| #include "compat_ioctl.h" | ||||
| 
 | ||||
| struct agp_front_data agp_fe; | ||||
| 
 | ||||
| @ -1017,7 +1019,7 @@ static long agp_ioctl(struct file *file, | ||||
| 	case AGPIOC_UNBIND: | ||||
| 		ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg); | ||||
| 		break; | ||||
| 	        | ||||
| 
 | ||||
| 	case AGPIOC_CHIPSET_FLUSH: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| @ -261,7 +261,8 @@ static int nvidia_remove_memory(struct agp_memory *mem, off_t pg_start, int type | ||||
| static void nvidia_tlbflush(struct agp_memory *mem) | ||||
| { | ||||
| 	unsigned long end; | ||||
| 	u32 wbc_reg, temp; | ||||
| 	u32 wbc_reg; | ||||
| 	u32 __maybe_unused temp; | ||||
| 	int i; | ||||
| 
 | ||||
| 	/* flush chipset */ | ||||
|  | ||||
| @ -262,13 +262,10 @@ static void serverworks_tlbflush(struct agp_memory *temp) | ||||
| 
 | ||||
| static int serverworks_configure(void) | ||||
| { | ||||
| 	struct aper_size_info_lvl2 *current_size; | ||||
| 	u32 temp; | ||||
| 	u8 enable_reg; | ||||
| 	u16 cap_reg; | ||||
| 
 | ||||
| 	current_size = A_SIZE_LVL2(agp_bridge->current_size); | ||||
| 
 | ||||
| 	/* Get the memory mapped registers */ | ||||
| 	pci_read_config_dword(agp_bridge->dev, serverworks_private.mm_addr_ofs, &temp); | ||||
| 	temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); | ||||
| @ -350,7 +347,7 @@ static int serverworks_insert_memory(struct agp_memory *mem, | ||||
| 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { | ||||
| 		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; | ||||
| 		cur_gatt = SVRWRKS_GET_GATT(addr); | ||||
| 		writel(agp_bridge->driver->mask_memory(agp_bridge,  | ||||
| 		writel(agp_bridge->driver->mask_memory(agp_bridge, | ||||
| 				page_to_phys(mem->pages[i]), mem->type), | ||||
| 		       cur_gatt+GET_GATT_OFF(addr)); | ||||
| 	} | ||||
|  | ||||
| @ -128,9 +128,6 @@ static int via_fetch_size_agp3(void) | ||||
| static int via_configure_agp3(void) | ||||
| { | ||||
| 	u32 temp; | ||||
| 	struct aper_size_info_16 *current_size; | ||||
| 
 | ||||
| 	current_size = A_SIZE_16(agp_bridge->current_size); | ||||
| 
 | ||||
| 	/* address to map to */ | ||||
| 	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, | ||||
|  | ||||
| @ -542,57 +542,45 @@ EXPORT_SYMBOL(dma_resv_copy_fences); | ||||
|  * dma_resv_get_fences - Get an object's shared and exclusive | ||||
|  * fences without update side lock held | ||||
|  * @obj: the reservation object | ||||
|  * @fence_excl: the returned exclusive fence (or NULL) | ||||
|  * @shared_count: the number of shared fences returned | ||||
|  * @shared: the array of shared fence ptrs returned (array is krealloc'd to | ||||
|  * the required size, and must be freed by caller) | ||||
|  * @write: true if we should return all fences | ||||
|  * @num_fences: the number of fences returned | ||||
|  * @fences: the array of fence ptrs returned (array is krealloc'd to the | ||||
|  * required size, and must be freed by caller) | ||||
|  * | ||||
|  * Retrieve all fences from the reservation object. If the pointer for the | ||||
|  * exclusive fence is not specified the fence is put into the array of the | ||||
|  * shared fences as well. Returns either zero or -ENOMEM. | ||||
|  * Retrieve all fences from the reservation object. | ||||
|  * Returns either zero or -ENOMEM. | ||||
|  */ | ||||
| int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **fence_excl, | ||||
| 			unsigned int *shared_count, struct dma_fence ***shared) | ||||
| int dma_resv_get_fences(struct dma_resv *obj, bool write, | ||||
| 			unsigned int *num_fences, struct dma_fence ***fences) | ||||
| { | ||||
| 	struct dma_resv_iter cursor; | ||||
| 	struct dma_fence *fence; | ||||
| 
 | ||||
| 	*shared_count = 0; | ||||
| 	*shared = NULL; | ||||
| 	*num_fences = 0; | ||||
| 	*fences = NULL; | ||||
| 
 | ||||
| 	if (fence_excl) | ||||
| 		*fence_excl = NULL; | ||||
| 
 | ||||
| 	dma_resv_iter_begin(&cursor, obj, true); | ||||
| 	dma_resv_iter_begin(&cursor, obj, write); | ||||
| 	dma_resv_for_each_fence_unlocked(&cursor, fence) { | ||||
| 
 | ||||
| 		if (dma_resv_iter_is_restarted(&cursor)) { | ||||
| 			unsigned int count; | ||||
| 
 | ||||
| 			while (*shared_count) | ||||
| 				dma_fence_put((*shared)[--(*shared_count)]); | ||||
| 			while (*num_fences) | ||||
| 				dma_fence_put((*fences)[--(*num_fences)]); | ||||
| 
 | ||||
| 			if (fence_excl) | ||||
| 				dma_fence_put(*fence_excl); | ||||
| 
 | ||||
| 			count = cursor.shared_count; | ||||
| 			count += fence_excl ? 0 : 1; | ||||
| 			count = cursor.shared_count + 1; | ||||
| 
 | ||||
| 			/* Eventually re-allocate the array */ | ||||
| 			*shared = krealloc_array(*shared, count, | ||||
| 			*fences = krealloc_array(*fences, count, | ||||
| 						 sizeof(void *), | ||||
| 						 GFP_KERNEL); | ||||
| 			if (count && !*shared) { | ||||
| 			if (count && !*fences) { | ||||
| 				dma_resv_iter_end(&cursor); | ||||
| 				return -ENOMEM; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		dma_fence_get(fence); | ||||
| 		if (dma_resv_iter_is_exclusive(&cursor) && fence_excl) | ||||
| 			*fence_excl = fence; | ||||
| 		else | ||||
| 			(*shared)[(*shared_count)++] = fence; | ||||
| 		(*fences)[(*num_fences)++] = dma_fence_get(fence); | ||||
| 	} | ||||
| 	dma_resv_iter_end(&cursor); | ||||
| 
 | ||||
|  | ||||
| @ -275,7 +275,7 @@ static int test_shared_for_each_unlocked(void *arg) | ||||
| 
 | ||||
| static int test_get_fences(void *arg, bool shared) | ||||
| { | ||||
| 	struct dma_fence *f, *excl = NULL, **fences = NULL; | ||||
| 	struct dma_fence *f, **fences = NULL; | ||||
| 	struct dma_resv resv; | ||||
| 	int r, i; | ||||
| 
 | ||||
| @ -304,35 +304,19 @@ static int test_get_fences(void *arg, bool shared) | ||||
| 	} | ||||
| 	dma_resv_unlock(&resv); | ||||
| 
 | ||||
| 	r = dma_resv_get_fences(&resv, &excl, &i, &fences); | ||||
| 	r = dma_resv_get_fences(&resv, shared, &i, &fences); | ||||
| 	if (r) { | ||||
| 		pr_err("get_fences failed\n"); | ||||
| 		goto err_free; | ||||
| 	} | ||||
| 
 | ||||
| 	if (shared) { | ||||
| 		if (excl != NULL) { | ||||
| 			pr_err("get_fences returned unexpected excl fence\n"); | ||||
| 			goto err_free; | ||||
| 		} | ||||
| 		if (i != 1 || fences[0] != f) { | ||||
| 			pr_err("get_fences returned unexpected shared fence\n"); | ||||
| 			goto err_free; | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (excl != f) { | ||||
| 			pr_err("get_fences returned unexpected excl fence\n"); | ||||
| 			goto err_free; | ||||
| 		} | ||||
| 		if (i != 0) { | ||||
| 			pr_err("get_fences returned unexpected shared fence\n"); | ||||
| 			goto err_free; | ||||
| 		} | ||||
| 	if (i != 1 || fences[0] != f) { | ||||
| 		pr_err("get_fences returned unexpected fence\n"); | ||||
| 		goto err_free; | ||||
| 	} | ||||
| 
 | ||||
| 	dma_fence_signal(f); | ||||
| err_free: | ||||
| 	dma_fence_put(excl); | ||||
| 	while (i--) | ||||
| 		dma_fence_put(fences[i]); | ||||
| 	kfree(fences); | ||||
|  | ||||
| @ -190,6 +190,10 @@ static long udmabuf_create(struct miscdevice *device, | ||||
| 		if (ubuf->pagecount > pglimit) | ||||
| 			goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ubuf->pagecount) | ||||
| 		goto err; | ||||
| 
 | ||||
| 	ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages), | ||||
| 				    GFP_KERNEL); | ||||
| 	if (!ubuf->pages) { | ||||
|  | ||||
| @ -99,7 +99,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si, | ||||
| 
 | ||||
| 	/* setup IORESOURCE_MEM as framebuffer memory */ | ||||
| 	memset(&res, 0, sizeof(res)); | ||||
| 	res.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||||
| 	res.flags = IORESOURCE_MEM; | ||||
| 	res.name = simplefb_resname; | ||||
| 	res.start = base; | ||||
| 	res.end = res.start + length - 1; | ||||
|  | ||||
| @ -68,6 +68,7 @@ config DRM_DEBUG_SELFTEST | ||||
| 	depends on DRM | ||||
| 	depends on DEBUG_KERNEL | ||||
| 	select PRIME_NUMBERS | ||||
| 	select DRM_DP_HELPER | ||||
| 	select DRM_LIB_RANDOM | ||||
| 	select DRM_KMS_HELPER | ||||
| 	select DRM_EXPORT_FOR_TESTS if m | ||||
| @ -80,6 +81,12 @@ config DRM_DEBUG_SELFTEST | ||||
| 
 | ||||
| 	  If in doubt, say "N". | ||||
| 
 | ||||
| config DRM_DP_HELPER | ||||
| 	tristate | ||||
| 	depends on DRM | ||||
| 	help | ||||
| 	  DRM helpers for DisplayPort. | ||||
| 
 | ||||
| config DRM_KMS_HELPER | ||||
| 	tristate | ||||
| 	depends on DRM | ||||
| @ -198,6 +205,12 @@ config DRM_TTM | ||||
| 	  GPU memory types. Will be enabled automatically if a device driver | ||||
| 	  uses it. | ||||
| 
 | ||||
| config DRM_BUDDY | ||||
| 	tristate | ||||
| 	depends on DRM | ||||
| 	help | ||||
| 	  A page based buddy allocator | ||||
| 
 | ||||
| config DRM_VRAM_HELPER | ||||
| 	tristate | ||||
| 	depends on DRM | ||||
| @ -236,6 +249,7 @@ config DRM_RADEON | ||||
| 	depends on DRM && PCI && MMU | ||||
| 	depends on AGP || !AGP | ||||
| 	select FW_LOADER | ||||
| 	select DRM_DP_HELPER | ||||
|         select DRM_KMS_HELPER | ||||
|         select DRM_TTM | ||||
| 	select DRM_TTM_HELPER | ||||
| @ -256,6 +270,7 @@ config DRM_AMDGPU | ||||
| 	tristate "AMD GPU" | ||||
| 	depends on DRM && PCI && MMU | ||||
| 	select FW_LOADER | ||||
| 	select DRM_DP_HELPER | ||||
| 	select DRM_KMS_HELPER | ||||
| 	select DRM_SCHED | ||||
| 	select DRM_TTM | ||||
|  | ||||
| @ -31,8 +31,6 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o | ||||
| drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o | ||||
| drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o drm_privacy_screen_x86.o | ||||
| 
 | ||||
| obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o | ||||
| 
 | ||||
| obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o | ||||
| 
 | ||||
| drm_cma_helper-y := drm_gem_cma_helper.o | ||||
| @ -42,27 +40,26 @@ obj-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_cma_helper.o | ||||
| drm_shmem_helper-y := drm_gem_shmem_helper.o | ||||
| obj-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_shmem_helper.o | ||||
| 
 | ||||
| obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o | ||||
| 
 | ||||
| drm_vram_helper-y := drm_gem_vram_helper.o | ||||
| obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o | ||||
| 
 | ||||
| drm_ttm_helper-y := drm_gem_ttm_helper.o | ||||
| obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o | ||||
| 
 | ||||
| drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o drm_dp_helper.o \
 | ||||
| drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \
 | ||||
| 		drm_dsc.o drm_encoder_slave.o drm_flip_work.o drm_hdcp.o \
 | ||||
| 		drm_probe_helper.o \
 | ||||
| 		drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
 | ||||
| 		drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
 | ||||
| 		drm_plane_helper.o drm_atomic_helper.o \
 | ||||
| 		drm_kms_helper_common.o \
 | ||||
| 		drm_simple_kms_helper.o drm_modeset_helper.o \
 | ||||
| 		drm_scdc_helper.o drm_gem_atomic_helper.o \
 | ||||
| 		drm_gem_framebuffer_helper.o \
 | ||||
| 		drm_atomic_state_helper.o drm_damage_helper.o \
 | ||||
| 		drm_format_helper.o drm_self_refresh_helper.o drm_rect.o | ||||
| 
 | ||||
| drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o | ||||
| drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o | ||||
| drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o | ||||
| drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o | ||||
| 
 | ||||
| obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o | ||||
| obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/ | ||||
| @ -72,6 +69,7 @@ obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o | ||||
| obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o | ||||
| obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o | ||||
| obj-y			+= arm/ | ||||
| obj-y			+= dp/ | ||||
| obj-$(CONFIG_DRM_TTM)	+= ttm/ | ||||
| obj-$(CONFIG_DRM_SCHED)	+= scheduler/ | ||||
| obj-$(CONFIG_DRM_TDFX)	+= tdfx/ | ||||
|  | ||||
| @ -26,7 +26,7 @@ | ||||
| 
 | ||||
| #include <drm/drm_edid.h> | ||||
| #include <drm/drm_fb_helper.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_probe_helper.h> | ||||
| #include <drm/amdgpu_drm.h> | ||||
| #include "amdgpu.h" | ||||
| @ -175,7 +175,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector) | ||||
| 
 | ||||
| 			/* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ | ||||
| 			if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { | ||||
| 				if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) && | ||||
| 				if ((connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) && | ||||
| 				    (mode_clock * 5/4 <= max_tmds_clock)) | ||||
| 					bpc = 10; | ||||
| 				else | ||||
|  | ||||
| @ -1274,14 +1274,11 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, | ||||
| 		/*
 | ||||
| 		 * Work around dma_resv shortcommings by wrapping up the | ||||
| 		 * submission in a dma_fence_chain and add it as exclusive | ||||
| 		 * fence, but first add the submission as shared fence to make | ||||
| 		 * sure that shared fences never signal before the exclusive | ||||
| 		 * one. | ||||
| 		 * fence. | ||||
| 		 */ | ||||
| 		dma_fence_chain_init(chain, dma_resv_excl_fence(resv), | ||||
| 				     dma_fence_get(p->fence), 1); | ||||
| 
 | ||||
| 		dma_resv_add_shared_fence(resv, p->fence); | ||||
| 		rcu_assign_pointer(resv->fence_excl, &chain->base); | ||||
| 		e->chain = NULL; | ||||
| 	} | ||||
|  | ||||
| @ -200,8 +200,10 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, | ||||
| 		goto unpin; | ||||
| 	} | ||||
| 
 | ||||
| 	r = dma_resv_get_fences(new_abo->tbo.base.resv, NULL, | ||||
| 				&work->shared_count, &work->shared); | ||||
| 	/* TODO: Unify this with other drivers */ | ||||
| 	r = dma_resv_get_fences(new_abo->tbo.base.resv, true, | ||||
| 				&work->shared_count, | ||||
| 				&work->shared); | ||||
| 	if (unlikely(r != 0)) { | ||||
| 		DRM_ERROR("failed to get fences for buffer\n"); | ||||
| 		goto unpin; | ||||
|  | ||||
| @ -226,12 +226,6 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj, | ||||
| 	if (!amdgpu_vm_ready(vm)) | ||||
| 		goto out_unlock; | ||||
| 
 | ||||
| 	fence = dma_resv_excl_fence(bo->tbo.base.resv); | ||||
| 	if (fence) { | ||||
| 		amdgpu_bo_fence(bo, fence, true); | ||||
| 		fence = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	r = amdgpu_vm_clear_freed(adev, vm, &fence); | ||||
| 	if (r || !fence) | ||||
| 		goto out_unlock; | ||||
|  | ||||
| @ -167,6 +167,7 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, | ||||
| 	return 0; | ||||
| 
 | ||||
| err_free: | ||||
| 	ttm_resource_fini(man, &node->base.base); | ||||
| 	kfree(node); | ||||
| 
 | ||||
| err_out: | ||||
| @ -198,6 +199,7 @@ static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, | ||||
| 	if (!(res->placement & TTM_PL_FLAG_TEMPORARY)) | ||||
| 		atomic64_sub(res->num_pages, &mgr->used); | ||||
| 
 | ||||
| 	ttm_resource_fini(man, res); | ||||
| 	kfree(node); | ||||
| } | ||||
| 
 | ||||
| @ -286,7 +288,8 @@ int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size) | ||||
| 	man->use_tt = true; | ||||
| 	man->func = &amdgpu_gtt_mgr_func; | ||||
| 
 | ||||
| 	ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT); | ||||
| 	ttm_resource_manager_init(man, &adev->mman.bdev, | ||||
| 				  gtt_size >> PAGE_SHIFT); | ||||
| 
 | ||||
| 	start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; | ||||
| 	size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; | ||||
|  | ||||
| @ -112,7 +112,7 @@ void amdgpu_pasid_free_delayed(struct dma_resv *resv, | ||||
| 	unsigned count; | ||||
| 	int r; | ||||
| 
 | ||||
| 	r = dma_resv_get_fences(resv, NULL, &count, &fences); | ||||
| 	r = dma_resv_get_fences(resv, true, &count, &fences); | ||||
| 	if (r) | ||||
| 		goto fallback; | ||||
| 
 | ||||
|  | ||||
| @ -33,7 +33,7 @@ | ||||
| #include <drm/drm_crtc.h> | ||||
| #include <drm/drm_edid.h> | ||||
| #include <drm/drm_encoder.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_fixed.h> | ||||
| #include <drm/drm_crtc_helper.h> | ||||
| #include <drm/drm_fb_helper.h> | ||||
| @ -44,7 +44,7 @@ | ||||
| #include <linux/hrtimer.h> | ||||
| #include "amdgpu_irq.h" | ||||
| 
 | ||||
| #include <drm/drm_dp_mst_helper.h> | ||||
| #include <drm/dp/drm_dp_mst_helper.h> | ||||
| #include "modules/inc/mod_freesync.h" | ||||
| #include "amdgpu_dm_irq_params.h" | ||||
| 
 | ||||
|  | ||||
| @ -95,6 +95,7 @@ static void amdgpu_preempt_mgr_del(struct ttm_resource_manager *man, | ||||
| 	struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man); | ||||
| 
 | ||||
| 	atomic64_sub(res->num_pages, &mgr->used); | ||||
| 	ttm_resource_fini(man, res); | ||||
| 	kfree(res); | ||||
| } | ||||
| 
 | ||||
| @ -152,7 +153,7 @@ int amdgpu_preempt_mgr_init(struct amdgpu_device *adev) | ||||
| 	man->use_tt = true; | ||||
| 	man->func = &amdgpu_preempt_mgr_func; | ||||
| 
 | ||||
| 	ttm_resource_manager_init(man, (1 << 30)); | ||||
| 	ttm_resource_manager_init(man, &adev->mman.bdev, (1 << 30)); | ||||
| 
 | ||||
| 	atomic64_set(&mgr->used, 0); | ||||
| 
 | ||||
|  | ||||
| @ -2087,7 +2087,7 @@ static int amdgpu_mm_vram_table_show(struct seq_file *m, void *unused) | ||||
| 							    TTM_PL_VRAM); | ||||
| 	struct drm_printer p = drm_seq_file_printer(m); | ||||
| 
 | ||||
| 	man->func->debug(man, &p); | ||||
| 	ttm_resource_manager_debug(man, &p); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -2105,7 +2105,7 @@ static int amdgpu_mm_tt_table_show(struct seq_file *m, void *unused) | ||||
| 							    TTM_PL_TT); | ||||
| 	struct drm_printer p = drm_seq_file_printer(m); | ||||
| 
 | ||||
| 	man->func->debug(man, &p); | ||||
| 	ttm_resource_manager_debug(man, &p); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -2116,7 +2116,7 @@ static int amdgpu_mm_gds_table_show(struct seq_file *m, void *unused) | ||||
| 							    AMDGPU_PL_GDS); | ||||
| 	struct drm_printer p = drm_seq_file_printer(m); | ||||
| 
 | ||||
| 	man->func->debug(man, &p); | ||||
| 	ttm_resource_manager_debug(man, &p); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -2127,7 +2127,7 @@ static int amdgpu_mm_gws_table_show(struct seq_file *m, void *unused) | ||||
| 							    AMDGPU_PL_GWS); | ||||
| 	struct drm_printer p = drm_seq_file_printer(m); | ||||
| 
 | ||||
| 	man->func->debug(man, &p); | ||||
| 	ttm_resource_manager_debug(man, &p); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -2138,7 +2138,7 @@ static int amdgpu_mm_oa_table_show(struct seq_file *m, void *unused) | ||||
| 							    AMDGPU_PL_OA); | ||||
| 	struct drm_printer p = drm_seq_file_printer(m); | ||||
| 
 | ||||
| 	man->func->debug(man, &p); | ||||
| 	ttm_resource_manager_debug(man, &p); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -472,6 +472,7 @@ error_free: | ||||
| 	while (i--) | ||||
| 		drm_mm_remove_node(&node->mm_nodes[i]); | ||||
| 	spin_unlock(&mgr->lock); | ||||
| 	ttm_resource_fini(man, &node->base); | ||||
| 	kvfree(node); | ||||
| 
 | ||||
| error_sub: | ||||
| @ -511,6 +512,7 @@ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, | ||||
| 	atomic64_sub(usage, &mgr->usage); | ||||
| 	atomic64_sub(vis_usage, &mgr->vis_usage); | ||||
| 
 | ||||
| 	ttm_resource_fini(man, res); | ||||
| 	kvfree(node); | ||||
| } | ||||
| 
 | ||||
| @ -689,7 +691,8 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev) | ||||
| 	struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; | ||||
| 	struct ttm_resource_manager *man = &mgr->manager; | ||||
| 
 | ||||
| 	ttm_resource_manager_init(man, adev->gmc.real_vram_size >> PAGE_SHIFT); | ||||
| 	ttm_resource_manager_init(man, &adev->mman.bdev, | ||||
| 				  adev->gmc.real_vram_size >> PAGE_SHIFT); | ||||
| 
 | ||||
| 	man->func = &amdgpu_vram_mgr_func; | ||||
| 
 | ||||
|  | ||||
| @ -34,7 +34,7 @@ | ||||
| #include "atombios_dp.h" | ||||
| #include "amdgpu_connectors.h" | ||||
| #include "amdgpu_atombios.h" | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| 
 | ||||
| /* move these to drm_dp_helper.c/h */ | ||||
| #define DP_LINK_CONFIGURATION_SIZE 9 | ||||
|  | ||||
| @ -76,7 +76,7 @@ | ||||
| #include <drm/drm_atomic.h> | ||||
| #include <drm/drm_atomic_uapi.h> | ||||
| #include <drm/drm_atomic_helper.h> | ||||
| #include <drm/drm_dp_mst_helper.h> | ||||
| #include <drm/dp/drm_dp_mst_helper.h> | ||||
| #include <drm/drm_fb_helper.h> | ||||
| #include <drm/drm_fourcc.h> | ||||
| #include <drm/drm_edid.h> | ||||
| @ -5856,7 +5856,7 @@ static void fill_stream_properties_from_drm_display_mode( | ||||
| 	else if (drm_mode_is_420_also(info, mode_in) | ||||
| 			&& aconnector->force_yuv420_output) | ||||
| 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; | ||||
| 	else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) | ||||
| 	else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444) | ||||
| 			&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) | ||||
| 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; | ||||
| 	else | ||||
|  | ||||
| @ -29,7 +29,7 @@ | ||||
| #include <drm/drm_atomic.h> | ||||
| #include <drm/drm_connector.h> | ||||
| #include <drm/drm_crtc.h> | ||||
| #include <drm/drm_dp_mst_helper.h> | ||||
| #include <drm/dp/drm_dp_mst_helper.h> | ||||
| #include <drm/drm_plane.h> | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
| @ -25,8 +25,8 @@ | ||||
| 
 | ||||
| #include <drm/drm_atomic.h> | ||||
| #include <drm/drm_atomic_helper.h> | ||||
| #include <drm/drm_dp_mst_helper.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_mst_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include "dm_services.h" | ||||
| #include "amdgpu.h" | ||||
| #include "amdgpu_dm.h" | ||||
|  | ||||
| @ -27,7 +27,7 @@ | ||||
| #include <dc_link.h> | ||||
| #include <inc/link_hwss.h> | ||||
| #include <inc/link_dpcd.h> | ||||
| #include "drm/drm_dp_helper.h" | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <dc_dp_types.h> | ||||
| #include "dm_helpers.h" | ||||
| 
 | ||||
|  | ||||
| @ -25,7 +25,7 @@ | ||||
| #include <drm/drm_dsc.h> | ||||
| #include "dc_hw_types.h" | ||||
| #include "dsc.h" | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include "dc.h" | ||||
| #include "rc_calc.h" | ||||
| #include "fixed31_32.h" | ||||
|  | ||||
| @ -36,7 +36,7 @@ | ||||
| #include <asm/byteorder.h> | ||||
| 
 | ||||
| #include <drm/drm_print.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| 
 | ||||
| #include "cgs_common.h" | ||||
| 
 | ||||
|  | ||||
| @ -26,7 +26,7 @@ | ||||
| #ifndef __DAL_DPCD_DEFS_H__ | ||||
| #define __DAL_DPCD_DEFS_H__ | ||||
| 
 | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #ifndef DP_SINK_HW_REVISION_START // can remove this once the define gets into linux drm_dp_helper.h
 | ||||
| #define DP_SINK_HW_REVISION_START 0x409 | ||||
| #endif | ||||
|  | ||||
| @ -30,7 +30,7 @@ | ||||
| #include "hdcp_log.h" | ||||
| 
 | ||||
| #include <drm/drm_hdcp.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| 
 | ||||
| enum mod_hdcp_trans_input_result { | ||||
| 	UNKNOWN = 0, | ||||
|  | ||||
| @ -1078,11 +1078,11 @@ static void d71_improc_update(struct komeda_component *c, | ||||
| 	mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; | ||||
| 
 | ||||
| 	/* config color format */ | ||||
| 	if (st->color_format == DRM_COLOR_FORMAT_YCRCB420) | ||||
| 	if (st->color_format == DRM_COLOR_FORMAT_YCBCR420) | ||||
| 		ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; | ||||
| 	else if (st->color_format == DRM_COLOR_FORMAT_YCRCB422) | ||||
| 	else if (st->color_format == DRM_COLOR_FORMAT_YCBCR422) | ||||
| 		ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422; | ||||
| 	else if (st->color_format == DRM_COLOR_FORMAT_YCRCB444) | ||||
| 	else if (st->color_format == DRM_COLOR_FORMAT_YCBCR444) | ||||
| 		ctrl |= IPS_CTRL_YUV; | ||||
| 
 | ||||
| 	malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl); | ||||
| @ -1144,11 +1144,11 @@ static int d71_improc_init(struct d71_dev *d71, | ||||
| 	improc = to_improc(c); | ||||
| 	improc->supported_color_depths = BIT(8) | BIT(10); | ||||
| 	improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 | | ||||
| 					  DRM_COLOR_FORMAT_YCRCB444 | | ||||
| 					  DRM_COLOR_FORMAT_YCRCB422; | ||||
| 					  DRM_COLOR_FORMAT_YCBCR444 | | ||||
| 					  DRM_COLOR_FORMAT_YCBCR422; | ||||
| 	value = malidp_read32(reg, BLK_INFO); | ||||
| 	if (value & IPS_INFO_CHD420) | ||||
| 		improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420; | ||||
| 		improc->supported_color_formats |= DRM_COLOR_FORMAT_YCBCR420; | ||||
| 
 | ||||
| 	improc->supports_csc = true; | ||||
| 	improc->supports_gamma = true; | ||||
|  | ||||
| @ -9,6 +9,7 @@ | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/component.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| #include <drm/drm_module.h> | ||||
| #include <drm/drm_of.h> | ||||
| #include "komeda_dev.h" | ||||
| #include "komeda_kms.h" | ||||
| @ -198,7 +199,7 @@ static struct platform_driver komeda_platform_driver = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| module_platform_driver(komeda_platform_driver); | ||||
| drm_module_platform_driver(komeda_platform_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>"); | ||||
| MODULE_DESCRIPTION("Komeda KMS driver"); | ||||
|  | ||||
| @ -30,6 +30,7 @@ | ||||
| #include <drm/drm_gem_cma_helper.h> | ||||
| #include <drm/drm_gem_framebuffer_helper.h> | ||||
| #include <drm/drm_modeset_helper.h> | ||||
| #include <drm/drm_module.h> | ||||
| #include <drm/drm_of.h> | ||||
| #include <drm/drm_probe_helper.h> | ||||
| #include <drm/drm_vblank.h> | ||||
| @ -434,7 +435,7 @@ static struct platform_driver hdlcd_platform_driver = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| module_platform_driver(hdlcd_platform_driver); | ||||
| drm_module_platform_driver(hdlcd_platform_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Liviu Dudau"); | ||||
| MODULE_DESCRIPTION("ARM HDLCD DRM driver"); | ||||
|  | ||||
| @ -25,6 +25,7 @@ | ||||
| #include <drm/drm_gem_cma_helper.h> | ||||
| #include <drm/drm_gem_framebuffer_helper.h> | ||||
| #include <drm/drm_modeset_helper.h> | ||||
| #include <drm/drm_module.h> | ||||
| #include <drm/drm_of.h> | ||||
| #include <drm/drm_probe_helper.h> | ||||
| #include <drm/drm_vblank.h> | ||||
| @ -1008,7 +1009,7 @@ static struct platform_driver malidp_platform_driver = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| module_platform_driver(malidp_platform_driver); | ||||
| drm_module_platform_driver(malidp_platform_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Liviu Dudau <Liviu.Dudau@arm.com>"); | ||||
| MODULE_DESCRIPTION("ARM Mali DP DRM driver"); | ||||
|  | ||||
| @ -34,6 +34,7 @@ | ||||
| #include <drm/drm_crtc_helper.h> | ||||
| #include <drm/drm_drv.h> | ||||
| #include <drm/drm_gem_vram_helper.h> | ||||
| #include <drm/drm_module.h> | ||||
| #include <drm/drm_probe_helper.h> | ||||
| 
 | ||||
| #include "ast_drv.h" | ||||
| @ -230,22 +231,7 @@ static struct pci_driver ast_pci_driver = { | ||||
| 	.driver.pm = &ast_pm_ops, | ||||
| }; | ||||
| 
 | ||||
| static int __init ast_init(void) | ||||
| { | ||||
| 	if (drm_firmware_drivers_only() && ast_modeset == -1) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (ast_modeset == 0) | ||||
| 		return -EINVAL; | ||||
| 	return pci_register_driver(&ast_pci_driver); | ||||
| } | ||||
| static void __exit ast_exit(void) | ||||
| { | ||||
| 	pci_unregister_driver(&ast_pci_driver); | ||||
| } | ||||
| 
 | ||||
| module_init(ast_init); | ||||
| module_exit(ast_exit); | ||||
| drm_module_pci_driver_if_modeset(ast_pci_driver, ast_modeset); | ||||
| 
 | ||||
| MODULE_AUTHOR(DRIVER_AUTHOR); | ||||
| MODULE_DESCRIPTION(DRIVER_DESC); | ||||
|  | ||||
| @ -209,6 +209,8 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) | ||||
| 			if (ast->chip == AST2500 && | ||||
| 			    scu_rev == 0x100)           /* ast2510 */ | ||||
| 				ast->support_wide_screen = true; | ||||
| 			if (ast->chip == AST2600)		/* ast2600 */ | ||||
| 				ast->support_wide_screen = true; | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| @ -471,7 +471,10 @@ static void ast_set_color_reg(struct ast_private *ast, | ||||
| static void ast_set_crtthd_reg(struct ast_private *ast) | ||||
| { | ||||
| 	/* Set Threshold */ | ||||
| 	if (ast->chip == AST2300 || ast->chip == AST2400 || | ||||
| 	if (ast->chip == AST2600) { | ||||
| 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0xe0); | ||||
| 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0xa0); | ||||
| 	} else if (ast->chip == AST2300 || ast->chip == AST2400 || | ||||
| 	    ast->chip == AST2500) { | ||||
| 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78); | ||||
| 		ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60); | ||||
|  | ||||
| @ -30,6 +30,7 @@ config DRM_CDNS_DSI | ||||
| config DRM_CHIPONE_ICN6211 | ||||
| 	tristate "Chipone ICN6211 MIPI-DSI/RGB Converter bridge" | ||||
| 	depends on OF | ||||
| 	depends on DRM_KMS_HELPER | ||||
| 	select DRM_MIPI_DSI | ||||
| 	select DRM_PANEL_BRIDGE | ||||
| 	help | ||||
| @ -183,6 +184,7 @@ config DRM_PARADE_PS8640 | ||||
| 	tristate "Parade PS8640 MIPI DSI to eDP Converter" | ||||
| 	depends on OF | ||||
| 	select DRM_DP_AUX_BUS | ||||
| 	select DRM_DP_HELPER | ||||
| 	select DRM_KMS_HELPER | ||||
| 	select DRM_MIPI_DSI | ||||
| 	select DRM_PANEL | ||||
| @ -253,6 +255,7 @@ config DRM_TOSHIBA_TC358764 | ||||
| config DRM_TOSHIBA_TC358767 | ||||
| 	tristate "Toshiba TC358767 eDP bridge" | ||||
| 	depends on OF | ||||
| 	select DRM_DP_HELPER | ||||
| 	select DRM_KMS_HELPER | ||||
| 	select REGMAP_I2C | ||||
| 	select DRM_PANEL | ||||
| @ -272,6 +275,7 @@ config DRM_TOSHIBA_TC358768 | ||||
| config DRM_TOSHIBA_TC358775 | ||||
| 	tristate "Toshiba TC358775 DSI/LVDS bridge" | ||||
| 	depends on OF | ||||
| 	select DRM_DP_HELPER | ||||
| 	select DRM_KMS_HELPER | ||||
| 	select REGMAP_I2C | ||||
| 	select DRM_PANEL | ||||
| @ -299,6 +303,7 @@ config DRM_TI_SN65DSI83 | ||||
| config DRM_TI_SN65DSI86 | ||||
| 	tristate "TI SN65DSI86 DSI to eDP bridge" | ||||
| 	depends on OF | ||||
| 	select DRM_DP_HELPER | ||||
| 	select DRM_KMS_HELPER | ||||
| 	select REGMAP_I2C | ||||
| 	select DRM_PANEL | ||||
|  | ||||
| @ -169,6 +169,7 @@ | ||||
| #define ADV7511_PACKET_ENABLE_SPARE2		BIT(1) | ||||
| #define ADV7511_PACKET_ENABLE_SPARE1		BIT(0) | ||||
| 
 | ||||
| #define ADV7535_REG_POWER2_HPD_OVERRIDE		BIT(6) | ||||
| #define ADV7511_REG_POWER2_HPD_SRC_MASK		0xc0 | ||||
| #define ADV7511_REG_POWER2_HPD_SRC_BOTH		0x00 | ||||
| #define ADV7511_REG_POWER2_HPD_SRC_HPD		0x40 | ||||
|  | ||||
| @ -223,7 +223,7 @@ static void adv7511_set_config_csc(struct adv7511 *adv7511, | ||||
| 		config.csc_coefficents = adv7511_csc_ycbcr_to_rgb; | ||||
| 
 | ||||
| 		if ((connector->display_info.color_formats & | ||||
| 		     DRM_COLOR_FORMAT_YCRCB422) && | ||||
| 		     DRM_COLOR_FORMAT_YCBCR422) && | ||||
| 		    config.hdmi_mode) { | ||||
| 			config.csc_enable = false; | ||||
| 			config.avi_infoframe.colorspace = | ||||
| @ -351,11 +351,17 @@ static void __adv7511_power_on(struct adv7511 *adv7511) | ||||
| 	 * from standby or are enabled. When the HPD goes low the adv7511 is | ||||
| 	 * reset and the outputs are disabled which might cause the monitor to | ||||
| 	 * go to standby again. To avoid this we ignore the HPD pin for the | ||||
| 	 * first few seconds after enabling the output. | ||||
| 	 * first few seconds after enabling the output. On the other hand | ||||
| 	 * adv7535 require to enable HPD Override bit for proper HPD. | ||||
| 	 */ | ||||
| 	regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||||
| 			   ADV7511_REG_POWER2_HPD_SRC_MASK, | ||||
| 			   ADV7511_REG_POWER2_HPD_SRC_NONE); | ||||
| 	if (adv7511->type == ADV7535) | ||||
| 		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||||
| 				   ADV7535_REG_POWER2_HPD_OVERRIDE, | ||||
| 				   ADV7535_REG_POWER2_HPD_OVERRIDE); | ||||
| 	else | ||||
| 		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||||
| 				   ADV7511_REG_POWER2_HPD_SRC_MASK, | ||||
| 				   ADV7511_REG_POWER2_HPD_SRC_NONE); | ||||
| } | ||||
| 
 | ||||
| static void adv7511_power_on(struct adv7511 *adv7511) | ||||
| @ -375,6 +381,10 @@ static void adv7511_power_on(struct adv7511 *adv7511) | ||||
| static void __adv7511_power_off(struct adv7511 *adv7511) | ||||
| { | ||||
| 	/* TODO: setup additional power down modes */ | ||||
| 	if (adv7511->type == ADV7535) | ||||
| 		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||||
| 				   ADV7535_REG_POWER2_HPD_OVERRIDE, 0); | ||||
| 
 | ||||
| 	regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, | ||||
| 			   ADV7511_POWER_POWER_DOWN, | ||||
| 			   ADV7511_POWER_POWER_DOWN); | ||||
| @ -672,9 +682,14 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) | ||||
| 			status = connector_status_disconnected; | ||||
| 	} else { | ||||
| 		/* Renable HPD sensing */ | ||||
| 		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||||
| 				   ADV7511_REG_POWER2_HPD_SRC_MASK, | ||||
| 				   ADV7511_REG_POWER2_HPD_SRC_BOTH); | ||||
| 		if (adv7511->type == ADV7535) | ||||
| 			regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||||
| 					   ADV7535_REG_POWER2_HPD_OVERRIDE, | ||||
| 					   ADV7535_REG_POWER2_HPD_OVERRIDE); | ||||
| 		else | ||||
| 			regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||||
| 					   ADV7511_REG_POWER2_HPD_SRC_MASK, | ||||
| 					   ADV7511_REG_POWER2_HPD_SRC_BOTH); | ||||
| 	} | ||||
| 
 | ||||
| 	adv7511->status = status; | ||||
|  | ||||
| @ -29,7 +29,7 @@ static void adv7511_dsi_config_timing_gen(struct adv7511 *adv) | ||||
| 	struct mipi_dsi_device *dsi = adv->dsi; | ||||
| 	struct drm_display_mode *mode = &adv->curr_mode; | ||||
| 	unsigned int hsw, hfp, hbp, vsw, vfp, vbp; | ||||
| 	u8 clock_div_by_lanes[] = { 6, 4, 3 };	/* 2, 3, 4 lanes */ | ||||
| 	static const u8 clock_div_by_lanes[] = { 6, 4, 3 };	/* 2, 3, 4 lanes */ | ||||
| 
 | ||||
| 	hsw = mode->hsync_end - mode->hsync_start; | ||||
| 	hfp = mode->hsync_start - mode->hdisplay; | ||||
|  | ||||
| @ -3,6 +3,7 @@ config DRM_ANALOGIX_ANX6345 | ||||
| 	tristate "Analogix ANX6345 bridge" | ||||
| 	depends on OF | ||||
| 	select DRM_ANALOGIX_DP | ||||
| 	select DRM_DP_HELPER | ||||
| 	select DRM_KMS_HELPER | ||||
| 	select REGMAP_I2C | ||||
| 	help | ||||
| @ -14,6 +15,7 @@ config DRM_ANALOGIX_ANX6345 | ||||
| config DRM_ANALOGIX_ANX78XX | ||||
| 	tristate "Analogix ANX78XX bridge" | ||||
| 	select DRM_ANALOGIX_DP | ||||
| 	select DRM_DP_HELPER | ||||
| 	select DRM_KMS_HELPER | ||||
| 	select REGMAP_I2C | ||||
| 	help | ||||
|  | ||||
| @ -22,7 +22,7 @@ | ||||
| #include <drm/drm_bridge.h> | ||||
| #include <drm/drm_crtc.h> | ||||
| #include <drm/drm_crtc_helper.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_edid.h> | ||||
| #include <drm/drm_of.h> | ||||
| #include <drm/drm_panel.h> | ||||
|  | ||||
| @ -21,7 +21,7 @@ | ||||
| #include <drm/drm_atomic_helper.h> | ||||
| #include <drm/drm_bridge.h> | ||||
| #include <drm/drm_crtc.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_edid.h> | ||||
| #include <drm/drm_print.h> | ||||
| #include <drm/drm_probe_helper.h> | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
| #include <linux/regmap.h> | ||||
| 
 | ||||
| #include <drm/drm.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_print.h> | ||||
| 
 | ||||
| #include "analogix-i2c-dptx.h" | ||||
|  | ||||
| @ -1537,9 +1537,9 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, | ||||
| 		video->color_depth = COLOR_8; | ||||
| 		break; | ||||
| 	} | ||||
| 	if (display_info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | ||||
| 	if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR444) | ||||
| 		video->color_space = COLOR_YCBCR444; | ||||
| 	else if (display_info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | ||||
| 	else if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422) | ||||
| 		video->color_space = COLOR_YCBCR422; | ||||
| 	else | ||||
| 		video->color_space = COLOR_RGB; | ||||
|  | ||||
| @ -10,7 +10,7 @@ | ||||
| #define _ANALOGIX_DP_CORE_H | ||||
| 
 | ||||
| #include <drm/drm_crtc.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| 
 | ||||
| #define DP_TIMEOUT_LOOP_COUNT 100 | ||||
| #define MAX_CR_LOOP 5 | ||||
|  | ||||
| @ -24,8 +24,9 @@ | ||||
| #include <drm/drm_atomic_helper.h> | ||||
| #include <drm/drm_bridge.h> | ||||
| #include <drm/drm_crtc_helper.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_edid.h> | ||||
| #include <drm/drm_hdcp.h> | ||||
| #include <drm/drm_mipi_dsi.h> | ||||
| #include <drm/drm_of.h> | ||||
| #include <drm/drm_panel.h> | ||||
| @ -213,6 +214,65 @@ static int wait_aux_op_finish(struct anx7625_data *ctx) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, | ||||
| 				 u32 address, u8 len, u8 *buf) | ||||
| { | ||||
| 	struct device *dev = &ctx->client->dev; | ||||
| 	int ret; | ||||
| 	u8 addrh, addrm, addrl; | ||||
| 	u8 cmd; | ||||
| 
 | ||||
| 	if (len > MAX_DPCD_BUFFER_SIZE) { | ||||
| 		dev_err(dev, "exceed aux buffer len.\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	addrl = address & 0xFF; | ||||
| 	addrm = (address >> 8) & 0xFF; | ||||
| 	addrh = (address >> 16) & 0xFF; | ||||
| 
 | ||||
| 	cmd = DPCD_CMD(len, DPCD_READ); | ||||
| 	cmd = ((len - 1) << 4) | 0x09; | ||||
| 
 | ||||
| 	/* Set command and length */ | ||||
| 	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				AP_AUX_COMMAND, cmd); | ||||
| 
 | ||||
| 	/* Set aux access address */ | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 AP_AUX_ADDR_7_0, addrl); | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 AP_AUX_ADDR_15_8, addrm); | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 AP_AUX_ADDR_19_16, addrh); | ||||
| 
 | ||||
| 	/* Enable aux access */ | ||||
| 	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client, | ||||
| 				AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN); | ||||
| 
 | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(dev, "cannot access aux related register.\n"); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	usleep_range(2000, 2100); | ||||
| 
 | ||||
| 	ret = wait_aux_op_finish(ctx); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "aux IO error: wait aux op finish.\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client, | ||||
| 				     AP_AUX_BUFF_START, len, buf); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(dev, "read dpcd register failed\n"); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int anx7625_video_mute_control(struct anx7625_data *ctx, | ||||
| 				      u8 status) | ||||
| { | ||||
| @ -669,6 +729,165 @@ static int anx7625_dpi_config(struct anx7625_data *ctx) | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int anx7625_read_flash_status(struct anx7625_data *ctx) | ||||
| { | ||||
| 	return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, R_RAM_CTRL); | ||||
| } | ||||
| 
 | ||||
| static int anx7625_hdcp_key_probe(struct anx7625_data *ctx) | ||||
| { | ||||
| 	int ret, val; | ||||
| 	struct device *dev = &ctx->client->dev; | ||||
| 	u8 ident[FLASH_BUF_LEN]; | ||||
| 
 | ||||
| 	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				FLASH_ADDR_HIGH, 0x91); | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 FLASH_ADDR_LOW, 0xA0); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(dev, "IO error : set key flash address.\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				FLASH_LEN_HIGH, (FLASH_BUF_LEN - 1) >> 8); | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 FLASH_LEN_LOW, (FLASH_BUF_LEN - 1) & 0xFF); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(dev, "IO error : set key flash len.\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				R_FLASH_RW_CTRL, FLASH_READ); | ||||
| 	ret |= readx_poll_timeout(anx7625_read_flash_status, | ||||
| 				  ctx, val, | ||||
| 				  ((val & FLASH_DONE) || (val < 0)), | ||||
| 				  2000, | ||||
| 				  2000 * 150); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "flash read access fail!\n"); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client, | ||||
| 				     FLASH_BUF_BASE_ADDR, | ||||
| 				     FLASH_BUF_LEN, ident); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(dev, "read flash data fail!\n"); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ident[29] == 0xFF && ident[30] == 0xFF && ident[31] == 0xFF) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int anx7625_hdcp_key_load(struct anx7625_data *ctx) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct device *dev = &ctx->client->dev; | ||||
| 
 | ||||
| 	/* Select HDCP 1.4 KEY */ | ||||
| 	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				R_BOOT_RETRY, 0x12); | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 FLASH_ADDR_HIGH, HDCP14KEY_START_ADDR >> 8); | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 FLASH_ADDR_LOW, HDCP14KEY_START_ADDR & 0xFF); | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 R_RAM_LEN_H, HDCP14KEY_SIZE >> 12); | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 R_RAM_LEN_L, HDCP14KEY_SIZE >> 4); | ||||
| 
 | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 R_RAM_ADDR_H, 0); | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 R_RAM_ADDR_L, 0); | ||||
| 	/* Enable HDCP 1.4 KEY load */ | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||||
| 				 R_RAM_CTRL, DECRYPT_EN | LOAD_START); | ||||
| 	dev_dbg(dev, "load HDCP 1.4 key done\n"); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int anx7625_hdcp_disable(struct anx7625_data *ctx) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct device *dev = &ctx->client->dev; | ||||
| 
 | ||||
| 	dev_dbg(dev, "disable HDCP 1.4\n"); | ||||
| 
 | ||||
| 	/* Disable HDCP */ | ||||
| 	ret = anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f); | ||||
| 	/* Try auth flag */ | ||||
| 	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10); | ||||
| 	/* Interrupt for DRM */ | ||||
| 	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01); | ||||
| 	if (ret < 0) | ||||
| 		dev_err(dev, "fail to disable HDCP\n"); | ||||
| 
 | ||||
| 	return anx7625_write_and(ctx, ctx->i2c.tx_p0_client, | ||||
| 				 TX_HDCP_CTRL0, ~HARD_AUTH_EN & 0xFF); | ||||
| } | ||||
| 
 | ||||
| static int anx7625_hdcp_enable(struct anx7625_data *ctx) | ||||
| { | ||||
| 	u8 bcap; | ||||
| 	int ret; | ||||
| 	struct device *dev = &ctx->client->dev; | ||||
| 
 | ||||
| 	ret = anx7625_hdcp_key_probe(ctx); | ||||
| 	if (ret) { | ||||
| 		dev_dbg(dev, "no key found, not to do hdcp\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Read downstream capability */ | ||||
| 	anx7625_aux_dpcd_read(ctx, 0x68028, 1, &bcap); | ||||
| 	if (!(bcap & 0x01)) { | ||||
| 		pr_warn("downstream not support HDCP 1.4, cap(%x).\n", bcap); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_dbg(dev, "enable HDCP 1.4\n"); | ||||
| 
 | ||||
| 	/* First clear HDCP state */ | ||||
| 	ret = anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | ||||
| 				TX_HDCP_CTRL0, | ||||
| 				KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN); | ||||
| 	usleep_range(1000, 1100); | ||||
| 	/* Second clear HDCP state */ | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | ||||
| 				 TX_HDCP_CTRL0, | ||||
| 				 KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN); | ||||
| 
 | ||||
| 	/* Set time for waiting KSVR */ | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | ||||
| 				 SP_TX_WAIT_KSVR_TIME, 0xc8); | ||||
| 	/* Set time for waiting R0 */ | ||||
| 	ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | ||||
| 				 SP_TX_WAIT_R0_TIME, 0xb0); | ||||
| 	ret |= anx7625_hdcp_key_load(ctx); | ||||
| 	if (ret) { | ||||
| 		pr_warn("prepare HDCP key failed.\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xee, 0x20); | ||||
| 
 | ||||
| 	/* Try auth flag */ | ||||
| 	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10); | ||||
| 	/* Interrupt for DRM */ | ||||
| 	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01); | ||||
| 	if (ret < 0) | ||||
| 		dev_err(dev, "fail to enable HDCP\n"); | ||||
| 
 | ||||
| 	return anx7625_write_or(ctx, ctx->i2c.tx_p0_client, | ||||
| 				TX_HDCP_CTRL0, HARD_AUTH_EN); | ||||
| } | ||||
| 
 | ||||
| static void anx7625_dp_start(struct anx7625_data *ctx) | ||||
| { | ||||
| 	int ret; | ||||
| @ -679,6 +898,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx) | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Disable HDCP */ | ||||
| 	anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f); | ||||
| 
 | ||||
| 	if (ctx->pdata.is_dpi) | ||||
| 		ret = anx7625_dpi_config(ctx); | ||||
| 	else | ||||
| @ -686,6 +908,10 @@ static void anx7625_dp_start(struct anx7625_data *ctx) | ||||
| 
 | ||||
| 	if (ret < 0) | ||||
| 		DRM_DEV_ERROR(dev, "MIPI phy setup error.\n"); | ||||
| 
 | ||||
| 	ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; | ||||
| 
 | ||||
| 	ctx->dp_en = 1; | ||||
| } | ||||
| 
 | ||||
| static void anx7625_dp_stop(struct anx7625_data *ctx) | ||||
| @ -705,6 +931,10 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) | ||||
| 	ret |= anx7625_video_mute_control(ctx, 1); | ||||
| 	if (ret < 0) | ||||
| 		DRM_DEV_ERROR(dev, "IO error : mute video fail\n"); | ||||
| 
 | ||||
| 	ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; | ||||
| 
 | ||||
| 	ctx->dp_en = 0; | ||||
| } | ||||
| 
 | ||||
| static int sp_tx_rst_aux(struct anx7625_data *ctx) | ||||
| @ -1098,9 +1328,18 @@ static void anx7625_init_gpio(struct anx7625_data *platform) | ||||
| 	/* Gpio for chip power enable */ | ||||
| 	platform->pdata.gpio_p_on = | ||||
| 		devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); | ||||
| 	if (IS_ERR_OR_NULL(platform->pdata.gpio_p_on)) { | ||||
| 		DRM_DEV_DEBUG_DRIVER(dev, "no enable gpio found\n"); | ||||
| 		platform->pdata.gpio_p_on = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Gpio for chip reset */ | ||||
| 	platform->pdata.gpio_reset = | ||||
| 		devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); | ||||
| 	if (IS_ERR_OR_NULL(platform->pdata.gpio_reset)) { | ||||
| 		DRM_DEV_DEBUG_DRIVER(dev, "no reset gpio found\n"); | ||||
| 		platform->pdata.gpio_reset = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (platform->pdata.gpio_p_on && platform->pdata.gpio_reset) { | ||||
| 		platform->pdata.low_power_mode = 1; | ||||
| @ -1601,9 +1840,27 @@ static int anx7625_audio_hook_plugged_cb(struct device *dev, void *data, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int anx7625_audio_get_eld(struct device *dev, void *data, | ||||
| 				 u8 *buf, size_t len) | ||||
| { | ||||
| 	struct anx7625_data *ctx = dev_get_drvdata(dev); | ||||
| 
 | ||||
| 	if (!ctx->connector) { | ||||
| 		dev_err(dev, "connector not initial\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_dbg(dev, "audio copy eld\n"); | ||||
| 	memcpy(buf, ctx->connector->eld, | ||||
| 	       min(sizeof(ctx->connector->eld), len)); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct hdmi_codec_ops anx7625_codec_ops = { | ||||
| 	.hw_params	= anx7625_audio_hw_params, | ||||
| 	.audio_shutdown = anx7625_audio_shutdown, | ||||
| 	.get_eld	= anx7625_audio_get_eld, | ||||
| 	.get_dai_id	= anx7625_hdmi_i2s_get_dai_id, | ||||
| 	.hook_plugged_cb = anx7625_audio_hook_plugged_cb, | ||||
| }; | ||||
| @ -1660,7 +1917,7 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) | ||||
| 	host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node); | ||||
| 	if (!host) { | ||||
| 		DRM_DEV_ERROR(dev, "fail to find dsi host.\n"); | ||||
| 		return -EINVAL; | ||||
| 		return -EPROBE_DEFER; | ||||
| 	} | ||||
| 
 | ||||
| 	dsi = devm_mipi_dsi_device_register_full(dev, host, &info); | ||||
| @ -1688,6 +1945,83 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void hdcp_check_work_func(struct work_struct *work) | ||||
| { | ||||
| 	u8 status; | ||||
| 	struct delayed_work *dwork; | ||||
| 	struct anx7625_data *ctx; | ||||
| 	struct device *dev; | ||||
| 	struct drm_device *drm_dev; | ||||
| 
 | ||||
| 	dwork = to_delayed_work(work); | ||||
| 	ctx = container_of(dwork, struct anx7625_data, hdcp_work); | ||||
| 	dev = &ctx->client->dev; | ||||
| 
 | ||||
| 	if (!ctx->connector) { | ||||
| 		dev_err(dev, "HDCP connector is null!"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	drm_dev = ctx->connector->dev; | ||||
| 	drm_modeset_lock(&drm_dev->mode_config.connection_mutex, NULL); | ||||
| 	mutex_lock(&ctx->hdcp_wq_lock); | ||||
| 
 | ||||
| 	status = anx7625_reg_read(ctx, ctx->i2c.tx_p0_client, 0); | ||||
| 	dev_dbg(dev, "sink HDCP status check: %.02x\n", status); | ||||
| 	if (status & BIT(1)) { | ||||
| 		ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_ENABLED; | ||||
| 		drm_hdcp_update_content_protection(ctx->connector, | ||||
| 						   ctx->hdcp_cp); | ||||
| 		dev_dbg(dev, "update CP to ENABLE\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_unlock(&ctx->hdcp_wq_lock); | ||||
| 	drm_modeset_unlock(&drm_dev->mode_config.connection_mutex); | ||||
| } | ||||
| 
 | ||||
| static int anx7625_connector_atomic_check(struct anx7625_data *ctx, | ||||
| 					  struct drm_connector_state *state) | ||||
| { | ||||
| 	struct device *dev = &ctx->client->dev; | ||||
| 	int cp; | ||||
| 
 | ||||
| 	dev_dbg(dev, "hdcp state check\n"); | ||||
| 	cp = state->content_protection; | ||||
| 
 | ||||
| 	if (cp == ctx->hdcp_cp) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (cp == DRM_MODE_CONTENT_PROTECTION_DESIRED) { | ||||
| 		if (ctx->dp_en) { | ||||
| 			dev_dbg(dev, "enable HDCP\n"); | ||||
| 			anx7625_hdcp_enable(ctx); | ||||
| 
 | ||||
| 			queue_delayed_work(ctx->hdcp_workqueue, | ||||
| 					   &ctx->hdcp_work, | ||||
| 					   msecs_to_jiffies(2000)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (cp == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { | ||||
| 		if (ctx->hdcp_cp != DRM_MODE_CONTENT_PROTECTION_ENABLED) { | ||||
| 			dev_err(dev, "current CP is not ENABLED\n"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		anx7625_hdcp_disable(ctx); | ||||
| 		ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; | ||||
| 		drm_hdcp_update_content_protection(ctx->connector, | ||||
| 						   ctx->hdcp_cp); | ||||
| 		dev_dbg(dev, "update CP to UNDESIRE\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	if (cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) { | ||||
| 		dev_err(dev, "Userspace illegal set to PROTECTION ENABLE\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int anx7625_bridge_attach(struct drm_bridge *bridge, | ||||
| 				 enum drm_bridge_attach_flags flags) | ||||
| { | ||||
| @ -1902,25 +2236,57 @@ static bool anx7625_bridge_mode_fixup(struct drm_bridge *bridge, | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void anx7625_bridge_enable(struct drm_bridge *bridge) | ||||
| static int anx7625_bridge_atomic_check(struct drm_bridge *bridge, | ||||
| 				       struct drm_bridge_state *bridge_state, | ||||
| 				       struct drm_crtc_state *crtc_state, | ||||
| 				       struct drm_connector_state *conn_state) | ||||
| { | ||||
| 	struct anx7625_data *ctx = bridge_to_anx7625(bridge); | ||||
| 	struct device *dev = &ctx->client->dev; | ||||
| 
 | ||||
| 	DRM_DEV_DEBUG_DRIVER(dev, "drm enable\n"); | ||||
| 	dev_dbg(dev, "drm bridge atomic check\n"); | ||||
| 
 | ||||
| 	anx7625_bridge_mode_fixup(bridge, &crtc_state->mode, | ||||
| 				  &crtc_state->adjusted_mode); | ||||
| 
 | ||||
| 	return anx7625_connector_atomic_check(ctx, conn_state); | ||||
| } | ||||
| 
 | ||||
| static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge, | ||||
| 					 struct drm_bridge_state *state) | ||||
| { | ||||
| 	struct anx7625_data *ctx = bridge_to_anx7625(bridge); | ||||
| 	struct device *dev = &ctx->client->dev; | ||||
| 	struct drm_connector *connector; | ||||
| 
 | ||||
| 	dev_dbg(dev, "drm atomic enable\n"); | ||||
| 
 | ||||
| 	if (!bridge->encoder) { | ||||
| 		dev_err(dev, "Parent encoder object not found"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	connector = drm_atomic_get_new_connector_for_encoder(state->base.state, | ||||
| 							     bridge->encoder); | ||||
| 	if (!connector) | ||||
| 		return; | ||||
| 
 | ||||
| 	ctx->connector = connector; | ||||
| 
 | ||||
| 	pm_runtime_get_sync(dev); | ||||
| 
 | ||||
| 	anx7625_dp_start(ctx); | ||||
| } | ||||
| 
 | ||||
| static void anx7625_bridge_disable(struct drm_bridge *bridge) | ||||
| static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, | ||||
| 					  struct drm_bridge_state *old) | ||||
| { | ||||
| 	struct anx7625_data *ctx = bridge_to_anx7625(bridge); | ||||
| 	struct device *dev = &ctx->client->dev; | ||||
| 
 | ||||
| 	DRM_DEV_DEBUG_DRIVER(dev, "drm disable\n"); | ||||
| 	dev_dbg(dev, "drm atomic disable\n"); | ||||
| 
 | ||||
| 	ctx->connector = NULL; | ||||
| 	anx7625_dp_stop(ctx); | ||||
| 
 | ||||
| 	pm_runtime_put_sync(dev); | ||||
| @ -1950,11 +2316,14 @@ static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge, | ||||
| 
 | ||||
| static const struct drm_bridge_funcs anx7625_bridge_funcs = { | ||||
| 	.attach = anx7625_bridge_attach, | ||||
| 	.disable = anx7625_bridge_disable, | ||||
| 	.mode_valid = anx7625_bridge_mode_valid, | ||||
| 	.mode_set = anx7625_bridge_mode_set, | ||||
| 	.mode_fixup = anx7625_bridge_mode_fixup, | ||||
| 	.enable = anx7625_bridge_enable, | ||||
| 	.atomic_check = anx7625_bridge_atomic_check, | ||||
| 	.atomic_enable = anx7625_bridge_atomic_enable, | ||||
| 	.atomic_disable = anx7625_bridge_atomic_disable, | ||||
| 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, | ||||
| 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, | ||||
| 	.atomic_reset = drm_atomic_helper_bridge_reset, | ||||
| 	.detect = anx7625_bridge_detect, | ||||
| 	.get_edid = anx7625_bridge_get_edid, | ||||
| }; | ||||
| @ -1962,40 +2331,54 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = { | ||||
| static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx, | ||||
| 					      struct i2c_client *client) | ||||
| { | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	ctx->i2c.tx_p0_client = i2c_new_dummy_device(client->adapter, | ||||
| 						     TX_P0_ADDR >> 1); | ||||
| 	if (!ctx->i2c.tx_p0_client) | ||||
| 		return -ENOMEM; | ||||
| 	if (IS_ERR(ctx->i2c.tx_p0_client)) | ||||
| 		return PTR_ERR(ctx->i2c.tx_p0_client); | ||||
| 
 | ||||
| 	ctx->i2c.tx_p1_client = i2c_new_dummy_device(client->adapter, | ||||
| 						     TX_P1_ADDR >> 1); | ||||
| 	if (!ctx->i2c.tx_p1_client) | ||||
| 	if (IS_ERR(ctx->i2c.tx_p1_client)) { | ||||
| 		err = PTR_ERR(ctx->i2c.tx_p1_client); | ||||
| 		goto free_tx_p0; | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->i2c.tx_p2_client = i2c_new_dummy_device(client->adapter, | ||||
| 						     TX_P2_ADDR >> 1); | ||||
| 	if (!ctx->i2c.tx_p2_client) | ||||
| 	if (IS_ERR(ctx->i2c.tx_p2_client)) { | ||||
| 		err = PTR_ERR(ctx->i2c.tx_p2_client); | ||||
| 		goto free_tx_p1; | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->i2c.rx_p0_client = i2c_new_dummy_device(client->adapter, | ||||
| 						     RX_P0_ADDR >> 1); | ||||
| 	if (!ctx->i2c.rx_p0_client) | ||||
| 	if (IS_ERR(ctx->i2c.rx_p0_client)) { | ||||
| 		err = PTR_ERR(ctx->i2c.rx_p0_client); | ||||
| 		goto free_tx_p2; | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->i2c.rx_p1_client = i2c_new_dummy_device(client->adapter, | ||||
| 						     RX_P1_ADDR >> 1); | ||||
| 	if (!ctx->i2c.rx_p1_client) | ||||
| 	if (IS_ERR(ctx->i2c.rx_p1_client)) { | ||||
| 		err = PTR_ERR(ctx->i2c.rx_p1_client); | ||||
| 		goto free_rx_p0; | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->i2c.rx_p2_client = i2c_new_dummy_device(client->adapter, | ||||
| 						     RX_P2_ADDR >> 1); | ||||
| 	if (!ctx->i2c.rx_p2_client) | ||||
| 	if (IS_ERR(ctx->i2c.rx_p2_client)) { | ||||
| 		err = PTR_ERR(ctx->i2c.rx_p2_client); | ||||
| 		goto free_rx_p1; | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->i2c.tcpc_client = i2c_new_dummy_device(client->adapter, | ||||
| 						    TCPC_INTERFACE_ADDR >> 1); | ||||
| 	if (!ctx->i2c.tcpc_client) | ||||
| 	if (IS_ERR(ctx->i2c.tcpc_client)) { | ||||
| 		err = PTR_ERR(ctx->i2c.tcpc_client); | ||||
| 		goto free_rx_p2; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| @ -2012,7 +2395,7 @@ free_tx_p1: | ||||
| free_tx_p0: | ||||
| 	i2c_unregister_device(ctx->i2c.tx_p0_client); | ||||
| 
 | ||||
| 	return -ENOMEM; | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static void anx7625_unregister_i2c_dummy_clients(struct anx7625_data *ctx) | ||||
| @ -2134,6 +2517,15 @@ static int anx7625_i2c_probe(struct i2c_client *client, | ||||
| 	anx7625_init_gpio(platform); | ||||
| 
 | ||||
| 	mutex_init(&platform->lock); | ||||
| 	mutex_init(&platform->hdcp_wq_lock); | ||||
| 
 | ||||
| 	INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func); | ||||
| 	platform->hdcp_workqueue = create_workqueue("hdcp workqueue"); | ||||
| 	if (!platform->hdcp_workqueue) { | ||||
| 		dev_err(dev, "fail to create work queue\n"); | ||||
| 		ret = -ENOMEM; | ||||
| 		goto free_platform; | ||||
| 	} | ||||
| 
 | ||||
| 	platform->pdata.intp_irq = client->irq; | ||||
| 	if (platform->pdata.intp_irq) { | ||||
| @ -2143,7 +2535,7 @@ static int anx7625_i2c_probe(struct i2c_client *client, | ||||
| 		if (!platform->workqueue) { | ||||
| 			DRM_DEV_ERROR(dev, "fail to create work queue\n"); | ||||
| 			ret = -ENOMEM; | ||||
| 			goto free_platform; | ||||
| 			goto free_hdcp_wq; | ||||
| 		} | ||||
| 
 | ||||
| 		ret = devm_request_threaded_irq(dev, platform->pdata.intp_irq, | ||||
| @ -2213,6 +2605,10 @@ free_wq: | ||||
| 	if (platform->workqueue) | ||||
| 		destroy_workqueue(platform->workqueue); | ||||
| 
 | ||||
| free_hdcp_wq: | ||||
| 	if (platform->hdcp_workqueue) | ||||
| 		destroy_workqueue(platform->hdcp_workqueue); | ||||
| 
 | ||||
| free_platform: | ||||
| 	kfree(platform); | ||||
| 
 | ||||
| @ -2228,6 +2624,12 @@ static int anx7625_i2c_remove(struct i2c_client *client) | ||||
| 	if (platform->pdata.intp_irq) | ||||
| 		destroy_workqueue(platform->workqueue); | ||||
| 
 | ||||
| 	if (platform->hdcp_workqueue) { | ||||
| 		cancel_delayed_work(&platform->hdcp_work); | ||||
| 		flush_workqueue(platform->workqueue); | ||||
| 		destroy_workqueue(platform->workqueue); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!platform->pdata.low_power_mode) | ||||
| 		pm_runtime_put_sync_suspend(&client->dev); | ||||
| 
 | ||||
|  | ||||
| @ -59,10 +59,23 @@ | ||||
| 
 | ||||
| /***************************************************************/ | ||||
| /* Register definition of device address 0x70 */ | ||||
| #define  I2C_ADDR_70_DPTX              0x70 | ||||
| #define TX_HDCP_CTRL0			0x01 | ||||
| #define STORE_AN			BIT(7) | ||||
| #define RX_REPEATER			BIT(6) | ||||
| #define RE_AUTHEN			BIT(5) | ||||
| #define SW_AUTH_OK			BIT(4) | ||||
| #define HARD_AUTH_EN			BIT(3) | ||||
| #define ENC_EN				BIT(2) | ||||
| #define BKSV_SRM_PASS			BIT(1) | ||||
| #define KSVLIST_VLD			BIT(0) | ||||
| 
 | ||||
| #define SP_TX_LINK_BW_SET_REG 0xA0 | ||||
| #define SP_TX_LANE_COUNT_SET_REG 0xA1 | ||||
| #define SP_TX_WAIT_R0_TIME		0x40 | ||||
| #define SP_TX_WAIT_KSVR_TIME		0x42 | ||||
| #define SP_TX_SYS_CTRL1_REG		0x80 | ||||
| #define HDCP2TX_FW_EN			BIT(4) | ||||
| 
 | ||||
| #define SP_TX_LINK_BW_SET_REG		0xA0 | ||||
| #define SP_TX_LANE_COUNT_SET_REG	0xA1 | ||||
| 
 | ||||
| #define M_VID_0 0xC0 | ||||
| #define M_VID_1 0xC1 | ||||
| @ -71,6 +84,12 @@ | ||||
| #define N_VID_1 0xC4 | ||||
| #define N_VID_2 0xC5 | ||||
| 
 | ||||
| #define KEY_START_ADDR			0x9000 | ||||
| #define KEY_RESERVED			416 | ||||
| 
 | ||||
| #define HDCP14KEY_START_ADDR		(KEY_START_ADDR + KEY_RESERVED) | ||||
| #define HDCP14KEY_SIZE			624 | ||||
| 
 | ||||
| /***************************************************************/ | ||||
| /* Register definition of device address 0x72 */ | ||||
| #define AUX_RST	0x04 | ||||
| @ -155,9 +174,43 @@ | ||||
| 
 | ||||
| #define  I2C_ADDR_7E_FLASH_CONTROLLER  0x7E | ||||
| 
 | ||||
| #define R_BOOT_RETRY		0x00 | ||||
| #define R_RAM_ADDR_H		0x01 | ||||
| #define R_RAM_ADDR_L		0x02 | ||||
| #define R_RAM_LEN_H		0x03 | ||||
| #define R_RAM_LEN_L		0x04 | ||||
| #define FLASH_LOAD_STA          0x05 | ||||
| #define FLASH_LOAD_STA_CHK	BIT(7) | ||||
| 
 | ||||
| #define R_RAM_CTRL              0x05 | ||||
| /* bit positions */ | ||||
| #define FLASH_DONE              BIT(7) | ||||
| #define BOOT_LOAD_DONE          BIT(6) | ||||
| #define CRC_OK                  BIT(5) | ||||
| #define LOAD_DONE               BIT(4) | ||||
| #define O_RW_DONE               BIT(3) | ||||
| #define FUSE_BUSY               BIT(2) | ||||
| #define DECRYPT_EN              BIT(1) | ||||
| #define LOAD_START              BIT(0) | ||||
| 
 | ||||
| #define FLASH_ADDR_HIGH         0x0F | ||||
| #define FLASH_ADDR_LOW          0x10 | ||||
| #define FLASH_LEN_HIGH          0x31 | ||||
| #define FLASH_LEN_LOW           0x32 | ||||
| #define R_FLASH_RW_CTRL         0x33 | ||||
| /* bit positions */ | ||||
| #define READ_DELAY_SELECT       BIT(7) | ||||
| #define GENERAL_INSTRUCTION_EN  BIT(6) | ||||
| #define FLASH_ERASE_EN          BIT(5) | ||||
| #define RDID_READ_EN            BIT(4) | ||||
| #define REMS_READ_EN            BIT(3) | ||||
| #define WRITE_STATUS_EN         BIT(2) | ||||
| #define FLASH_READ              BIT(1) | ||||
| #define FLASH_WRITE             BIT(0) | ||||
| 
 | ||||
| #define FLASH_BUF_BASE_ADDR     0x60 | ||||
| #define FLASH_BUF_LEN           0x20 | ||||
| 
 | ||||
| #define  XTAL_FRQ_SEL    0x3F | ||||
| /* bit field positions */ | ||||
| #define  XTAL_FRQ_SEL_POS    5 | ||||
| @ -184,10 +237,15 @@ | ||||
| #define AP_AUX_CTRL_ADDRONLY 0x20 | ||||
| 
 | ||||
| #define AP_AUX_BUFF_START 0x15 | ||||
| #define PIXEL_CLOCK_L 0x25 | ||||
| #define PIXEL_CLOCK_H 0x26 | ||||
| #define PIXEL_CLOCK_L	0x25 | ||||
| #define PIXEL_CLOCK_H	0x26 | ||||
| 
 | ||||
| #define AP_AUX_COMMAND	0x27  /* com+len */ | ||||
| #define LENGTH_SHIFT	4 | ||||
| #define DPCD_READ	0x09 | ||||
| #define DPCD_WRITE	0x08 | ||||
| #define DPCD_CMD(len, cmd)	((((len) - 1) << LENGTH_SHIFT) | (cmd)) | ||||
| 
 | ||||
| #define AP_AUX_COMMAND 0x27  /* com+len */ | ||||
| /* Bit 0&1: 3D video structure */ | ||||
| /* 0x01: frame packing,  0x02:Line alternative, 0x03:Side-by-side(full) */ | ||||
| #define AP_AV_STATUS 0x28 | ||||
| @ -392,21 +450,29 @@ struct anx7625_data { | ||||
| 	struct platform_device *audio_pdev; | ||||
| 	int hpd_status; | ||||
| 	int hpd_high_cnt; | ||||
| 	int dp_en; | ||||
| 	int hdcp_cp; | ||||
| 	/* Lock for work queue */ | ||||
| 	struct mutex lock; | ||||
| 	struct i2c_client *client; | ||||
| 	struct anx7625_i2c_client i2c; | ||||
| 	struct i2c_client *last_client; | ||||
| 	struct timer_list hdcp_timer; | ||||
| 	struct s_edid_data slimport_edid_p; | ||||
| 	struct device *codec_dev; | ||||
| 	hdmi_codec_plugged_cb plugged_cb; | ||||
| 	struct work_struct work; | ||||
| 	struct workqueue_struct *workqueue; | ||||
| 	struct delayed_work hdcp_work; | ||||
| 	struct workqueue_struct *hdcp_workqueue; | ||||
| 	/* Lock for hdcp work queue */ | ||||
| 	struct mutex hdcp_wq_lock; | ||||
| 	char edid_block; | ||||
| 	struct display_timing dt; | ||||
| 	u8 display_timing_valid; | ||||
| 	struct drm_bridge bridge; | ||||
| 	u8 bridge_attached; | ||||
| 	struct drm_connector *connector; | ||||
| 	struct mipi_dsi_device *dsi; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| # SPDX-License-Identifier: GPL-2.0-only | ||||
| config DRM_CDNS_MHDP8546 | ||||
| 	tristate "Cadence DPI/DP bridge" | ||||
| 	select DRM_DP_HELPER | ||||
| 	select DRM_KMS_HELPER | ||||
| 	select DRM_PANEL_BRIDGE | ||||
| 	depends on OF | ||||
|  | ||||
| @ -41,7 +41,7 @@ | ||||
| #include <drm/drm_bridge.h> | ||||
| #include <drm/drm_connector.h> | ||||
| #include <drm/drm_crtc_helper.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_hdcp.h> | ||||
| #include <drm/drm_modeset_helper_vtables.h> | ||||
| #include <drm/drm_print.h> | ||||
| @ -1553,13 +1553,13 @@ static u32 cdns_mhdp_get_bpp(struct cdns_mhdp_display_fmt *fmt) | ||||
| 
 | ||||
| 	switch (fmt->color_format) { | ||||
| 	case DRM_COLOR_FORMAT_RGB444: | ||||
| 	case DRM_COLOR_FORMAT_YCRCB444: | ||||
| 	case DRM_COLOR_FORMAT_YCBCR444: | ||||
| 		bpp = fmt->bpc * 3; | ||||
| 		break; | ||||
| 	case DRM_COLOR_FORMAT_YCRCB422: | ||||
| 	case DRM_COLOR_FORMAT_YCBCR422: | ||||
| 		bpp = fmt->bpc * 2; | ||||
| 		break; | ||||
| 	case DRM_COLOR_FORMAT_YCRCB420: | ||||
| 	case DRM_COLOR_FORMAT_YCBCR420: | ||||
| 		bpp = fmt->bpc * 3 / 2; | ||||
| 		break; | ||||
| 	default: | ||||
| @ -1767,8 +1767,8 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, | ||||
| 	 * If YCBCR supported and stream not SD, use ITU709 | ||||
| 	 * Need to handle ITU version with YCBCR420 when supported | ||||
| 	 */ | ||||
| 	if ((pxlfmt == DRM_COLOR_FORMAT_YCRCB444 || | ||||
| 	     pxlfmt == DRM_COLOR_FORMAT_YCRCB422) && mode->crtc_vdisplay >= 720) | ||||
| 	if ((pxlfmt == DRM_COLOR_FORMAT_YCBCR444 || | ||||
| 	     pxlfmt == DRM_COLOR_FORMAT_YCBCR422) && mode->crtc_vdisplay >= 720) | ||||
| 		misc0 = DP_YCBCR_COEFFICIENTS_ITU709; | ||||
| 
 | ||||
| 	bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt); | ||||
| @ -1778,15 +1778,15 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, | ||||
| 		pxl_repr = CDNS_DP_FRAMER_RGB << CDNS_DP_FRAMER_PXL_FORMAT; | ||||
| 		misc0 |= DP_COLOR_FORMAT_RGB; | ||||
| 		break; | ||||
| 	case DRM_COLOR_FORMAT_YCRCB444: | ||||
| 	case DRM_COLOR_FORMAT_YCBCR444: | ||||
| 		pxl_repr = CDNS_DP_FRAMER_YCBCR444 << CDNS_DP_FRAMER_PXL_FORMAT; | ||||
| 		misc0 |= DP_COLOR_FORMAT_YCbCr444 | DP_TEST_DYNAMIC_RANGE_CEA; | ||||
| 		break; | ||||
| 	case DRM_COLOR_FORMAT_YCRCB422: | ||||
| 	case DRM_COLOR_FORMAT_YCBCR422: | ||||
| 		pxl_repr = CDNS_DP_FRAMER_YCBCR422 << CDNS_DP_FRAMER_PXL_FORMAT; | ||||
| 		misc0 |= DP_COLOR_FORMAT_YCbCr422 | DP_TEST_DYNAMIC_RANGE_CEA; | ||||
| 		break; | ||||
| 	case DRM_COLOR_FORMAT_YCRCB420: | ||||
| 	case DRM_COLOR_FORMAT_YCBCR420: | ||||
| 		pxl_repr = CDNS_DP_FRAMER_YCBCR420 << CDNS_DP_FRAMER_PXL_FORMAT; | ||||
| 		break; | ||||
| 	default: | ||||
| @ -1882,7 +1882,7 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, | ||||
| 	if (mhdp->display_fmt.y_only) | ||||
| 		misc1 |= CDNS_DP_TEST_COLOR_FORMAT_RAW_Y_ONLY; | ||||
| 	/* Use VSC SDP for Y420 */ | ||||
| 	if (pxlfmt == DRM_COLOR_FORMAT_YCRCB420) | ||||
| 	if (pxlfmt == DRM_COLOR_FORMAT_YCBCR420) | ||||
| 		misc1 = CDNS_DP_TEST_VSC_SDP; | ||||
| 
 | ||||
| 	cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_MISC(stream_id), | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
| 
 | ||||
| #include <drm/drm_bridge.h> | ||||
| #include <drm/drm_connector.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| 
 | ||||
| struct clk; | ||||
| struct device; | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
|  * Author: Jagan Teki <jagan@amarulasolutions.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <drm/drm_atomic_helper.h> | ||||
| #include <drm/drm_of.h> | ||||
| #include <drm/drm_print.h> | ||||
| #include <drm/drm_mipi_dsi.h> | ||||
| @ -30,6 +31,7 @@ | ||||
| struct chipone { | ||||
| 	struct device *dev; | ||||
| 	struct drm_bridge bridge; | ||||
| 	struct drm_display_mode mode; | ||||
| 	struct drm_bridge *panel_bridge; | ||||
| 	struct gpio_desc *enable_gpio; | ||||
| 	struct regulator *vdd1; | ||||
| @ -42,11 +44,6 @@ static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge) | ||||
| 	return container_of(bridge, struct chipone, bridge); | ||||
| } | ||||
| 
 | ||||
| static struct drm_display_mode *bridge_to_mode(struct drm_bridge *bridge) | ||||
| { | ||||
| 	return &bridge->encoder->crtc->state->adjusted_mode; | ||||
| } | ||||
| 
 | ||||
| static inline int chipone_dsi_write(struct chipone *icn,  const void *seq, | ||||
| 				    size_t len) | ||||
| { | ||||
| @ -61,10 +58,11 @@ static inline int chipone_dsi_write(struct chipone *icn,  const void *seq, | ||||
| 		chipone_dsi_write(icn, d, ARRAY_SIZE(d));	\ | ||||
| 	} | ||||
| 
 | ||||
| static void chipone_enable(struct drm_bridge *bridge) | ||||
| static void chipone_atomic_enable(struct drm_bridge *bridge, | ||||
| 				  struct drm_bridge_state *old_bridge_state) | ||||
| { | ||||
| 	struct chipone *icn = bridge_to_chipone(bridge); | ||||
| 	struct drm_display_mode *mode = bridge_to_mode(bridge); | ||||
| 	struct drm_display_mode *mode = &icn->mode; | ||||
| 
 | ||||
| 	ICN6211_DSI(icn, 0x7a, 0xc1); | ||||
| 
 | ||||
| @ -114,7 +112,8 @@ static void chipone_enable(struct drm_bridge *bridge) | ||||
| 	usleep_range(10000, 11000); | ||||
| } | ||||
| 
 | ||||
| static void chipone_pre_enable(struct drm_bridge *bridge) | ||||
| static void chipone_atomic_pre_enable(struct drm_bridge *bridge, | ||||
| 				      struct drm_bridge_state *old_bridge_state) | ||||
| { | ||||
| 	struct chipone *icn = bridge_to_chipone(bridge); | ||||
| 	int ret; | ||||
| @ -145,7 +144,8 @@ static void chipone_pre_enable(struct drm_bridge *bridge) | ||||
| 	usleep_range(10000, 11000); | ||||
| } | ||||
| 
 | ||||
| static void chipone_post_disable(struct drm_bridge *bridge) | ||||
| static void chipone_atomic_post_disable(struct drm_bridge *bridge, | ||||
| 					struct drm_bridge_state *old_bridge_state) | ||||
| { | ||||
| 	struct chipone *icn = bridge_to_chipone(bridge); | ||||
| 
 | ||||
| @ -161,6 +161,15 @@ static void chipone_post_disable(struct drm_bridge *bridge) | ||||
| 	gpiod_set_value(icn->enable_gpio, 0); | ||||
| } | ||||
| 
 | ||||
| static void chipone_mode_set(struct drm_bridge *bridge, | ||||
| 			     const struct drm_display_mode *mode, | ||||
| 			     const struct drm_display_mode *adjusted_mode) | ||||
| { | ||||
| 	struct chipone *icn = bridge_to_chipone(bridge); | ||||
| 
 | ||||
| 	drm_mode_copy(&icn->mode, adjusted_mode); | ||||
| } | ||||
| 
 | ||||
| static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) | ||||
| { | ||||
| 	struct chipone *icn = bridge_to_chipone(bridge); | ||||
| @ -169,10 +178,14 @@ static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flag | ||||
| } | ||||
| 
 | ||||
| static const struct drm_bridge_funcs chipone_bridge_funcs = { | ||||
| 	.attach = chipone_attach, | ||||
| 	.post_disable = chipone_post_disable, | ||||
| 	.pre_enable = chipone_pre_enable, | ||||
| 	.enable = chipone_enable, | ||||
| 	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state, | ||||
| 	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state, | ||||
| 	.atomic_reset		= drm_atomic_helper_bridge_reset, | ||||
| 	.atomic_pre_enable	= chipone_atomic_pre_enable, | ||||
| 	.atomic_enable		= chipone_atomic_enable, | ||||
| 	.atomic_post_disable	= chipone_atomic_post_disable, | ||||
| 	.mode_set		= chipone_mode_set, | ||||
| 	.attach			= chipone_attach, | ||||
| }; | ||||
| 
 | ||||
| static int chipone_parse_dt(struct chipone *icn) | ||||
|  | ||||
| @ -936,9 +936,6 @@ static int it66121_probe(struct i2c_client *client, | ||||
| 		return -EPROBE_DEFER; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ctx->next_bridge) | ||||
| 		return -EPROBE_DEFER; | ||||
| 
 | ||||
| 	i2c_set_clientdata(client, ctx); | ||||
| 	mutex_init(&ctx->lock); | ||||
| 
 | ||||
|  | ||||
| @ -1090,7 +1090,7 @@ static int lt9611_probe(struct i2c_client *client, | ||||
| 	if (!lt9611) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	lt9611->dev = &client->dev; | ||||
| 	lt9611->dev = dev; | ||||
| 	lt9611->client = client; | ||||
| 	lt9611->sleep = false; | ||||
| 
 | ||||
| @ -1100,7 +1100,7 @@ static int lt9611_probe(struct i2c_client *client, | ||||
| 		return PTR_ERR(lt9611->regmap); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = lt9611_parse_dt(&client->dev, lt9611); | ||||
| 	ret = lt9611_parse_dt(dev, lt9611); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "failed to parse device tree\n"); | ||||
| 		return ret; | ||||
|  | ||||
| @ -860,7 +860,7 @@ static int lt9611uxc_probe(struct i2c_client *client, | ||||
| 	if (!lt9611uxc) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	lt9611uxc->dev = &client->dev; | ||||
| 	lt9611uxc->dev = dev; | ||||
| 	lt9611uxc->client = client; | ||||
| 	mutex_init(<9611uxc->ocm_lock); | ||||
| 
 | ||||
| @ -870,7 +870,7 @@ static int lt9611uxc_probe(struct i2c_client *client, | ||||
| 		return PTR_ERR(lt9611uxc->regmap); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = lt9611uxc_parse_dt(&client->dev, lt9611uxc); | ||||
| 	ret = lt9611uxc_parse_dt(dev, lt9611uxc); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "failed to parse device tree\n"); | ||||
| 		return ret; | ||||
|  | ||||
| @ -65,7 +65,6 @@ struct nwl_dsi_transfer { | ||||
| struct nwl_dsi { | ||||
| 	struct drm_bridge bridge; | ||||
| 	struct mipi_dsi_host dsi_host; | ||||
| 	struct drm_bridge *panel_bridge; | ||||
| 	struct device *dev; | ||||
| 	struct phy *phy; | ||||
| 	union phy_configure_opts phy_cfg; | ||||
| @ -924,13 +923,11 @@ static int nwl_dsi_bridge_attach(struct drm_bridge *bridge, | ||||
| 		if (IS_ERR(panel_bridge)) | ||||
| 			return PTR_ERR(panel_bridge); | ||||
| 	} | ||||
| 	dsi->panel_bridge = panel_bridge; | ||||
| 
 | ||||
| 	if (!dsi->panel_bridge) | ||||
| 	if (!panel_bridge) | ||||
| 		return -EPROBE_DEFER; | ||||
| 
 | ||||
| 	return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge, | ||||
| 				 flags); | ||||
| 	return drm_bridge_attach(bridge->encoder, panel_bridge, bridge, flags); | ||||
| } | ||||
| 
 | ||||
| static void nwl_dsi_bridge_detach(struct drm_bridge *bridge) | ||||
| @ -1206,6 +1203,7 @@ static int nwl_dsi_probe(struct platform_device *pdev) | ||||
| 
 | ||||
| 	ret = nwl_dsi_select_input(dsi); | ||||
| 	if (ret < 0) { | ||||
| 		pm_runtime_disable(dev); | ||||
| 		mipi_dsi_host_unregister(&dsi->dsi_host); | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| @ -14,8 +14,8 @@ | ||||
| #include <linux/regulator/consumer.h> | ||||
| 
 | ||||
| #include <drm/drm_bridge.h> | ||||
| #include <drm/drm_dp_aux_bus.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_aux_bus.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_mipi_dsi.h> | ||||
| #include <drm/drm_of.h> | ||||
| #include <drm/drm_panel.h> | ||||
| @ -102,6 +102,7 @@ struct ps8640 { | ||||
| 	struct regulator_bulk_data supplies[2]; | ||||
| 	struct gpio_desc *gpio_reset; | ||||
| 	struct gpio_desc *gpio_powerdown; | ||||
| 	struct device_link *link; | ||||
| 	bool pre_enabled; | ||||
| }; | ||||
| 
 | ||||
| @ -456,14 +457,36 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge, | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ps_bridge->link = device_link_add(bridge->dev->dev, dev, DL_FLAG_STATELESS); | ||||
| 	if (!ps_bridge->link) { | ||||
| 		dev_err(dev, "failed to create device link"); | ||||
| 		ret = -EINVAL; | ||||
| 		goto err_devlink; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Attach the panel-bridge to the dsi bridge */ | ||||
| 	return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, | ||||
| 				 &ps_bridge->bridge, flags); | ||||
| 	ret = drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, | ||||
| 				&ps_bridge->bridge, flags); | ||||
| 	if (ret) | ||||
| 		goto err_bridge_attach; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err_bridge_attach: | ||||
| 	device_link_del(ps_bridge->link); | ||||
| err_devlink: | ||||
| 	drm_dp_aux_unregister(&ps_bridge->aux); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void ps8640_bridge_detach(struct drm_bridge *bridge) | ||||
| { | ||||
| 	drm_dp_aux_unregister(&bridge_to_ps8640(bridge)->aux); | ||||
| 	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); | ||||
| 
 | ||||
| 	drm_dp_aux_unregister(&ps_bridge->aux); | ||||
| 	if (ps_bridge->link) | ||||
| 		device_link_del(ps_bridge->link); | ||||
| } | ||||
| 
 | ||||
| static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, | ||||
|  | ||||
| @ -166,10 +166,12 @@ struct sii902x { | ||||
| 	struct i2c_client *i2c; | ||||
| 	struct regmap *regmap; | ||||
| 	struct drm_bridge bridge; | ||||
| 	struct drm_bridge *next_bridge; | ||||
| 	struct drm_connector connector; | ||||
| 	struct gpio_desc *reset_gpio; | ||||
| 	struct i2c_mux_core *i2cmux; | ||||
| 	struct regulator_bulk_data supplies[2]; | ||||
| 	bool sink_is_hdmi; | ||||
| 	/*
 | ||||
| 	 * Mutex protects audio and video functions from interfering | ||||
| 	 * each other, by keeping their i2c command sequences atomic. | ||||
| @ -245,10 +247,8 @@ static void sii902x_reset(struct sii902x *sii902x) | ||||
| 	gpiod_set_value(sii902x->reset_gpio, 0); | ||||
| } | ||||
| 
 | ||||
| static enum drm_connector_status | ||||
| sii902x_connector_detect(struct drm_connector *connector, bool force) | ||||
| static enum drm_connector_status sii902x_detect(struct sii902x *sii902x) | ||||
| { | ||||
| 	struct sii902x *sii902x = connector_to_sii902x(connector); | ||||
| 	unsigned int status; | ||||
| 
 | ||||
| 	mutex_lock(&sii902x->mutex); | ||||
| @ -261,6 +261,14 @@ sii902x_connector_detect(struct drm_connector *connector, bool force) | ||||
| 	       connector_status_connected : connector_status_disconnected; | ||||
| } | ||||
| 
 | ||||
| static enum drm_connector_status | ||||
| sii902x_connector_detect(struct drm_connector *connector, bool force) | ||||
| { | ||||
| 	struct sii902x *sii902x = connector_to_sii902x(connector); | ||||
| 
 | ||||
| 	return sii902x_detect(sii902x); | ||||
| } | ||||
| 
 | ||||
| static const struct drm_connector_funcs sii902x_connector_funcs = { | ||||
| 	.detect = sii902x_connector_detect, | ||||
| 	.fill_modes = drm_helper_probe_single_connector_modes, | ||||
| @ -270,42 +278,40 @@ static const struct drm_connector_funcs sii902x_connector_funcs = { | ||||
| 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||||
| }; | ||||
| 
 | ||||
| static int sii902x_get_modes(struct drm_connector *connector) | ||||
| static struct edid *sii902x_get_edid(struct sii902x *sii902x, | ||||
| 				     struct drm_connector *connector) | ||||
| { | ||||
| 	struct sii902x *sii902x = connector_to_sii902x(connector); | ||||
| 	u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; | ||||
| 	u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; | ||||
| 	struct edid *edid; | ||||
| 	int num = 0, ret; | ||||
| 
 | ||||
| 	mutex_lock(&sii902x->mutex); | ||||
| 
 | ||||
| 	edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); | ||||
| 	drm_connector_update_edid_property(connector, edid); | ||||
| 	if (edid) { | ||||
| 		if (drm_detect_hdmi_monitor(edid)) | ||||
| 			output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; | ||||
| 			sii902x->sink_is_hdmi = true; | ||||
| 		else | ||||
| 			sii902x->sink_is_hdmi = false; | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_unlock(&sii902x->mutex); | ||||
| 
 | ||||
| 	return edid; | ||||
| } | ||||
| 
 | ||||
| static int sii902x_get_modes(struct drm_connector *connector) | ||||
| { | ||||
| 	struct sii902x *sii902x = connector_to_sii902x(connector); | ||||
| 	struct edid *edid; | ||||
| 	int num = 0; | ||||
| 
 | ||||
| 	edid = sii902x_get_edid(sii902x, connector); | ||||
| 	drm_connector_update_edid_property(connector, edid); | ||||
| 	if (edid) { | ||||
| 		num = drm_add_edid_modes(connector, edid); | ||||
| 		kfree(edid); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = drm_display_info_set_bus_formats(&connector->display_info, | ||||
| 					       &bus_format, 1); | ||||
| 	if (ret) | ||||
| 		goto error_out; | ||||
| 
 | ||||
| 	ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, | ||||
| 				 SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); | ||||
| 	if (ret) | ||||
| 		goto error_out; | ||||
| 
 | ||||
| 	ret = num; | ||||
| 
 | ||||
| error_out: | ||||
| 	mutex_unlock(&sii902x->mutex); | ||||
| 
 | ||||
| 	return ret; | ||||
| 	return num; | ||||
| } | ||||
| 
 | ||||
| static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector, | ||||
| @ -354,12 +360,16 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, | ||||
| 				    const struct drm_display_mode *adj) | ||||
| { | ||||
| 	struct sii902x *sii902x = bridge_to_sii902x(bridge); | ||||
| 	u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; | ||||
| 	struct regmap *regmap = sii902x->regmap; | ||||
| 	u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; | ||||
| 	struct hdmi_avi_infoframe frame; | ||||
| 	u16 pixel_clock_10kHz = adj->clock / 10; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (sii902x->sink_is_hdmi) | ||||
| 		output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; | ||||
| 
 | ||||
| 	buf[0] = pixel_clock_10kHz & 0xff; | ||||
| 	buf[1] = pixel_clock_10kHz >> 8; | ||||
| 	buf[2] = drm_mode_vrefresh(adj); | ||||
| @ -375,6 +385,11 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, | ||||
| 
 | ||||
| 	mutex_lock(&sii902x->mutex); | ||||
| 
 | ||||
| 	ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, | ||||
| 				 SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); | ||||
| 	if (ret) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10); | ||||
| 	if (ret) | ||||
| 		goto out; | ||||
| @ -405,13 +420,13 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge, | ||||
| 				 enum drm_bridge_attach_flags flags) | ||||
| { | ||||
| 	struct sii902x *sii902x = bridge_to_sii902x(bridge); | ||||
| 	u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; | ||||
| 	struct drm_device *drm = bridge->dev; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { | ||||
| 		DRM_ERROR("Fix bridge driver to make connector optional!"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) | ||||
| 		return drm_bridge_attach(bridge->encoder, sii902x->next_bridge, | ||||
| 					 bridge, flags); | ||||
| 
 | ||||
| 	drm_connector_helper_add(&sii902x->connector, | ||||
| 				 &sii902x_connector_helper_funcs); | ||||
| @ -433,16 +448,38 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge, | ||||
| 	else | ||||
| 		sii902x->connector.polled = DRM_CONNECTOR_POLL_CONNECT; | ||||
| 
 | ||||
| 	ret = drm_display_info_set_bus_formats(&sii902x->connector.display_info, | ||||
| 					       &bus_format, 1); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	drm_connector_attach_encoder(&sii902x->connector, bridge->encoder); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static enum drm_connector_status sii902x_bridge_detect(struct drm_bridge *bridge) | ||||
| { | ||||
| 	struct sii902x *sii902x = bridge_to_sii902x(bridge); | ||||
| 
 | ||||
| 	return sii902x_detect(sii902x); | ||||
| } | ||||
| 
 | ||||
| static struct edid *sii902x_bridge_get_edid(struct drm_bridge *bridge, | ||||
| 					    struct drm_connector *connector) | ||||
| { | ||||
| 	struct sii902x *sii902x = bridge_to_sii902x(bridge); | ||||
| 
 | ||||
| 	return sii902x_get_edid(sii902x, connector); | ||||
| } | ||||
| 
 | ||||
| static const struct drm_bridge_funcs sii902x_bridge_funcs = { | ||||
| 	.attach = sii902x_bridge_attach, | ||||
| 	.mode_set = sii902x_bridge_mode_set, | ||||
| 	.disable = sii902x_bridge_disable, | ||||
| 	.enable = sii902x_bridge_enable, | ||||
| 	.detect = sii902x_bridge_detect, | ||||
| 	.get_edid = sii902x_bridge_get_edid, | ||||
| }; | ||||
| 
 | ||||
| static int sii902x_mute(struct sii902x *sii902x, bool mute) | ||||
| @ -829,8 +866,12 @@ static irqreturn_t sii902x_interrupt(int irq, void *data) | ||||
| 
 | ||||
| 	mutex_unlock(&sii902x->mutex); | ||||
| 
 | ||||
| 	if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev) | ||||
| 	if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev) { | ||||
| 		drm_helper_hpd_irq_event(sii902x->bridge.dev); | ||||
| 		drm_bridge_hpd_notify(&sii902x->bridge, (status & SII902X_PLUGGED_STATUS) | ||||
| 								? connector_status_connected | ||||
| 								: connector_status_disconnected); | ||||
| 	} | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| @ -1001,6 +1042,11 @@ static int sii902x_init(struct sii902x *sii902x) | ||||
| 	sii902x->bridge.funcs = &sii902x_bridge_funcs; | ||||
| 	sii902x->bridge.of_node = dev->of_node; | ||||
| 	sii902x->bridge.timings = &default_sii902x_timings; | ||||
| 	sii902x->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID; | ||||
| 
 | ||||
| 	if (sii902x->i2c->irq > 0) | ||||
| 		sii902x->bridge.ops |= DRM_BRIDGE_OP_HPD; | ||||
| 
 | ||||
| 	drm_bridge_add(&sii902x->bridge); | ||||
| 
 | ||||
| 	sii902x_audio_codec_init(sii902x, dev); | ||||
| @ -1022,6 +1068,7 @@ static int sii902x_probe(struct i2c_client *client, | ||||
| 			 const struct i2c_device_id *id) | ||||
| { | ||||
| 	struct device *dev = &client->dev; | ||||
| 	struct device_node *endpoint; | ||||
| 	struct sii902x *sii902x; | ||||
| 	int ret; | ||||
| 
 | ||||
| @ -1049,6 +1096,28 @@ static int sii902x_probe(struct i2c_client *client, | ||||
| 		return PTR_ERR(sii902x->reset_gpio); | ||||
| 	} | ||||
| 
 | ||||
| 	endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1); | ||||
| 	if (endpoint) { | ||||
| 		struct device_node *remote = of_graph_get_remote_port_parent(endpoint); | ||||
| 
 | ||||
| 		of_node_put(endpoint); | ||||
| 		if (!remote) { | ||||
| 			dev_err(dev, "Endpoint in port@1 unconnected\n"); | ||||
| 			return -ENODEV; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!of_device_is_available(remote)) { | ||||
| 			dev_err(dev, "port@1 remote device is disabled\n"); | ||||
| 			of_node_put(remote); | ||||
| 			return -ENODEV; | ||||
| 		} | ||||
| 
 | ||||
| 		sii902x->next_bridge = of_drm_find_bridge(remote); | ||||
| 		of_node_put(remote); | ||||
| 		if (!sii902x->next_bridge) | ||||
| 			return -EPROBE_DEFER; | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_init(&sii902x->mutex); | ||||
| 
 | ||||
| 	sii902x->supplies[0].supply = "iovcc"; | ||||
|  | ||||
| @ -2120,7 +2120,7 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx) | ||||
| 	if (ret) { | ||||
| 		dev_err(ctx->dev, "Failed to register RC device\n"); | ||||
| 		ctx->error = ret; | ||||
| 		rc_free_device(ctx->rc_dev); | ||||
| 		rc_free_device(rc_dev); | ||||
| 		return; | ||||
| 	} | ||||
| 	ctx->rc_dev = rc_dev; | ||||
|  | ||||
| @ -2540,7 +2540,7 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, | ||||
| 	struct drm_display_mode *mode = &crtc_state->mode; | ||||
| 	u8 max_bpc = conn_state->max_requested_bpc; | ||||
| 	bool is_hdmi2_sink = info->hdmi.scdc.supported || | ||||
| 			     (info->color_formats & DRM_COLOR_FORMAT_YCRCB420); | ||||
| 			     (info->color_formats & DRM_COLOR_FORMAT_YCBCR420); | ||||
| 	u32 *output_fmts; | ||||
| 	unsigned int i = 0; | ||||
| 
 | ||||
| @ -2594,36 +2594,36 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (max_bpc >= 16 && info->bpc == 16) { | ||||
| 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | ||||
| 		if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) | ||||
| 			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; | ||||
| 
 | ||||
| 		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; | ||||
| 	} | ||||
| 
 | ||||
| 	if (max_bpc >= 12 && info->bpc >= 12) { | ||||
| 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | ||||
| 		if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) | ||||
| 			output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; | ||||
| 
 | ||||
| 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | ||||
| 		if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) | ||||
| 			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; | ||||
| 
 | ||||
| 		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; | ||||
| 	} | ||||
| 
 | ||||
| 	if (max_bpc >= 10 && info->bpc >= 10) { | ||||
| 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | ||||
| 		if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) | ||||
| 			output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; | ||||
| 
 | ||||
| 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | ||||
| 		if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) | ||||
| 			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; | ||||
| 
 | ||||
| 		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; | ||||
| 	} | ||||
| 
 | ||||
| 	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | ||||
| 	if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) | ||||
| 		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; | ||||
| 
 | ||||
| 	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | ||||
| 	if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) | ||||
| 		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; | ||||
| 
 | ||||
| 	/* Default 8bit RGB fallback */ | ||||
|  | ||||
| @ -871,7 +871,8 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) | ||||
| 	dsi_write(dsi, DSI_INT_MSK1, 0); | ||||
| } | ||||
| 
 | ||||
| static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) | ||||
| static void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge, | ||||
| 						   struct drm_bridge_state *old_bridge_state) | ||||
| { | ||||
| 	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); | ||||
| 	const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; | ||||
| @ -978,7 +979,8 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, | ||||
| 		dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode); | ||||
| } | ||||
| 
 | ||||
| static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) | ||||
| static void dw_mipi_dsi_bridge_atomic_enable(struct drm_bridge *bridge, | ||||
| 					     struct drm_bridge_state *old_bridge_state) | ||||
| { | ||||
| 	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); | ||||
| 
 | ||||
| @ -998,7 +1000,10 @@ dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, | ||||
| 	enum drm_mode_status mode_status = MODE_OK; | ||||
| 
 | ||||
| 	if (pdata->mode_valid) | ||||
| 		mode_status = pdata->mode_valid(pdata->priv_data, mode); | ||||
| 		mode_status = pdata->mode_valid(pdata->priv_data, mode, | ||||
| 						dsi->mode_flags, | ||||
| 						dw_mipi_dsi_get_lanes(dsi), | ||||
| 						dsi->format); | ||||
| 
 | ||||
| 	return mode_status; | ||||
| } | ||||
| @ -1032,11 +1037,14 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge, | ||||
| } | ||||
| 
 | ||||
| static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = { | ||||
| 	.mode_set     = dw_mipi_dsi_bridge_mode_set, | ||||
| 	.enable	      = dw_mipi_dsi_bridge_enable, | ||||
| 	.post_disable = dw_mipi_dsi_bridge_post_disable, | ||||
| 	.mode_valid   = dw_mipi_dsi_bridge_mode_valid, | ||||
| 	.attach	      = dw_mipi_dsi_bridge_attach, | ||||
| 	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state, | ||||
| 	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state, | ||||
| 	.atomic_reset		= drm_atomic_helper_bridge_reset, | ||||
| 	.atomic_enable		= dw_mipi_dsi_bridge_atomic_enable, | ||||
| 	.atomic_post_disable	= dw_mipi_dsi_bridge_post_atomic_disable, | ||||
| 	.mode_set		= dw_mipi_dsi_bridge_mode_set, | ||||
| 	.mode_valid		= dw_mipi_dsi_bridge_mode_valid, | ||||
| 	.attach			= dw_mipi_dsi_bridge_attach, | ||||
| }; | ||||
| 
 | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| @ -1199,6 +1207,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, | ||||
| 	ret = mipi_dsi_host_register(&dsi->dsi_host); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to register MIPI host: %d\n", ret); | ||||
| 		pm_runtime_disable(dev); | ||||
| 		dw_mipi_dsi_debugfs_remove(dsi); | ||||
| 		return ERR_PTR(ret); | ||||
| 	} | ||||
|  | ||||
| @ -27,7 +27,7 @@ | ||||
| 
 | ||||
| #include <drm/drm_atomic_helper.h> | ||||
| #include <drm/drm_bridge.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_edid.h> | ||||
| #include <drm/drm_of.h> | ||||
| #include <drm/drm_panel.h> | ||||
|  | ||||
| @ -22,7 +22,7 @@ | ||||
| #include <drm/drm_atomic_helper.h> | ||||
| #include <drm/drm_bridge.h> | ||||
| #include <drm/drm_crtc_helper.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_mipi_dsi.h> | ||||
| #include <drm/drm_of.h> | ||||
| #include <drm/drm_panel.h> | ||||
| @ -241,7 +241,7 @@ static inline u32 TC358775_LVCFG_PCLKDIV(uint32_t val) | ||||
| } | ||||
| 
 | ||||
| #define TC358775_LVCFG_LVDLINK__MASK                         0x00000002 | ||||
| #define TC358775_LVCFG_LVDLINK__SHIFT                        0 | ||||
| #define TC358775_LVCFG_LVDLINK__SHIFT                        1 | ||||
| static inline u32 TC358775_LVCFG_LVDLINK(uint32_t val) | ||||
| { | ||||
| 	return ((val) << TC358775_LVCFG_LVDLINK__SHIFT) & | ||||
|  | ||||
| @ -33,6 +33,7 @@ | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/of_graph.h> | ||||
| #include <linux/regmap.h> | ||||
| #include <linux/regulator/consumer.h> | ||||
| 
 | ||||
| #include <drm/drm_atomic_helper.h> | ||||
| #include <drm/drm_bridge.h> | ||||
| @ -143,6 +144,7 @@ struct sn65dsi83 { | ||||
| 	struct mipi_dsi_device		*dsi; | ||||
| 	struct drm_bridge		*panel_bridge; | ||||
| 	struct gpio_desc		*enable_gpio; | ||||
| 	struct regulator		*vcc; | ||||
| 	int				dsi_lanes; | ||||
| 	bool				lvds_dual_link; | ||||
| 	bool				lvds_dual_link_even_odd_swap; | ||||
| @ -337,6 +339,12 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, | ||||
| 	u16 val; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = regulator_enable(ctx->vcc); | ||||
| 	if (ret) { | ||||
| 		dev_err(ctx->dev, "Failed to enable vcc: %d\n", ret); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Deassert reset */ | ||||
| 	gpiod_set_value(ctx->enable_gpio, 1); | ||||
| 	usleep_range(1000, 1100); | ||||
| @ -486,11 +494,16 @@ static void sn65dsi83_atomic_disable(struct drm_bridge *bridge, | ||||
| 				     struct drm_bridge_state *old_bridge_state) | ||||
| { | ||||
| 	struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ | ||||
| 	gpiod_set_value(ctx->enable_gpio, 0); | ||||
| 	usleep_range(10000, 11000); | ||||
| 
 | ||||
| 	ret = regulator_disable(ctx->vcc); | ||||
| 	if (ret) | ||||
| 		dev_err(ctx->dev, "Failed to disable vcc: %d\n", ret); | ||||
| 
 | ||||
| 	regcache_mark_dirty(ctx->regmap); | ||||
| } | ||||
| 
 | ||||
| @ -560,10 +573,14 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) | ||||
| 	ctx->host_node = of_graph_get_remote_port_parent(endpoint); | ||||
| 	of_node_put(endpoint); | ||||
| 
 | ||||
| 	if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) | ||||
| 		return -EINVAL; | ||||
| 	if (!ctx->host_node) | ||||
| 		return -ENODEV; | ||||
| 	if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) { | ||||
| 		ret = -EINVAL; | ||||
| 		goto err_put_node; | ||||
| 	} | ||||
| 	if (!ctx->host_node) { | ||||
| 		ret = -ENODEV; | ||||
| 		goto err_put_node; | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->lvds_dual_link = false; | ||||
| 	ctx->lvds_dual_link_even_odd_swap = false; | ||||
| @ -590,16 +607,27 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) | ||||
| 
 | ||||
| 	ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, &panel_bridge); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 		goto err_put_node; | ||||
| 	if (panel) { | ||||
| 		panel_bridge = devm_drm_panel_bridge_add(dev, panel); | ||||
| 		if (IS_ERR(panel_bridge)) | ||||
| 			return PTR_ERR(panel_bridge); | ||||
| 		if (IS_ERR(panel_bridge)) { | ||||
| 			ret = PTR_ERR(panel_bridge); | ||||
| 			goto err_put_node; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->panel_bridge = panel_bridge; | ||||
| 
 | ||||
| 	ctx->vcc = devm_regulator_get(dev, "vcc"); | ||||
| 	if (IS_ERR(ctx->vcc)) | ||||
| 		return dev_err_probe(dev, PTR_ERR(ctx->vcc), | ||||
| 				     "Failed to get supply 'vcc'\n"); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err_put_node: | ||||
| 	of_node_put(ctx->host_node); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int sn65dsi83_host_attach(struct sn65dsi83 *ctx) | ||||
| @ -662,7 +690,8 @@ static int sn65dsi83_probe(struct i2c_client *client, | ||||
| 	} | ||||
| 
 | ||||
| 	/* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ | ||||
| 	ctx->enable_gpio = devm_gpiod_get(ctx->dev, "enable", GPIOD_OUT_LOW); | ||||
| 	ctx->enable_gpio = devm_gpiod_get_optional(ctx->dev, "enable", | ||||
| 						   GPIOD_OUT_LOW); | ||||
| 	if (IS_ERR(ctx->enable_gpio)) | ||||
| 		return PTR_ERR(ctx->enable_gpio); | ||||
| 
 | ||||
| @ -673,8 +702,10 @@ static int sn65dsi83_probe(struct i2c_client *client, | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ctx->regmap = devm_regmap_init_i2c(client, &sn65dsi83_regmap_config); | ||||
| 	if (IS_ERR(ctx->regmap)) | ||||
| 		return PTR_ERR(ctx->regmap); | ||||
| 	if (IS_ERR(ctx->regmap)) { | ||||
| 		ret = PTR_ERR(ctx->regmap); | ||||
| 		goto err_put_node; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_set_drvdata(dev, ctx); | ||||
| 	i2c_set_clientdata(client, ctx); | ||||
| @ -691,6 +722,8 @@ static int sn65dsi83_probe(struct i2c_client *client, | ||||
| 
 | ||||
| err_remove_bridge: | ||||
| 	drm_bridge_remove(&ctx->bridge); | ||||
| err_put_node: | ||||
| 	of_node_put(ctx->host_node); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -26,8 +26,8 @@ | ||||
| #include <drm/drm_atomic.h> | ||||
| #include <drm/drm_atomic_helper.h> | ||||
| #include <drm/drm_bridge.h> | ||||
| #include <drm/drm_dp_aux_bus.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_aux_bus.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_mipi_dsi.h> | ||||
| #include <drm/drm_of.h> | ||||
| #include <drm/drm_panel.h> | ||||
|  | ||||
							
								
								
									
										9
									
								
								drivers/gpu/drm/dp/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								drivers/gpu/drm/dp/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| # SPDX-License-Identifier: MIT
 | ||||
| 
 | ||||
| obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o | ||||
| 
 | ||||
| drm_dp_helper-y := drm_dp.o drm_dp_dual_mode_helper.o drm_dp_helper_mod.o drm_dp_mst_topology.o | ||||
| drm_dp_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o | ||||
| drm_dp_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o | ||||
| 
 | ||||
| obj-$(CONFIG_DRM_DP_HELPER) += drm_dp_helper.o | ||||
| @ -29,13 +29,13 @@ | ||||
| #include <linux/sched.h> | ||||
| #include <linux/seq_file.h> | ||||
| 
 | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_print.h> | ||||
| #include <drm/drm_vblank.h> | ||||
| #include <drm/drm_dp_mst_helper.h> | ||||
| #include <drm/dp/drm_dp_mst_helper.h> | ||||
| #include <drm/drm_panel.h> | ||||
| 
 | ||||
| #include "drm_crtc_helper_internal.h" | ||||
| #include "drm_dp_helper_internal.h" | ||||
| 
 | ||||
| struct dp_aux_backlight { | ||||
| 	struct backlight_device *base; | ||||
| @ -19,8 +19,8 @@ | ||||
| #include <linux/pm_domain.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| 
 | ||||
| #include <drm/drm_dp_aux_bus.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_aux_bus.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * dp_aux_ep_match() - The match function for the dp_aux_bus. | ||||
| @ -36,11 +36,11 @@ | ||||
| #include <linux/uio.h> | ||||
| 
 | ||||
| #include <drm/drm_crtc.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/drm_dp_mst_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_mst_helper.h> | ||||
| #include <drm/drm_print.h> | ||||
| 
 | ||||
| #include "drm_crtc_helper_internal.h" | ||||
| #include "drm_dp_helper_internal.h" | ||||
| 
 | ||||
| struct drm_dp_aux_dev { | ||||
| 	unsigned index; | ||||
| @ -13,7 +13,7 @@ | ||||
| 
 | ||||
| #include <drm/drm_connector.h> | ||||
| #include <drm/drm_device.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * Unfortunately it turns out that we have a chicken-and-egg situation | ||||
| @ -28,7 +28,7 @@ | ||||
| #include <linux/string.h> | ||||
| 
 | ||||
| #include <drm/drm_device.h> | ||||
| #include <drm/drm_dp_dual_mode_helper.h> | ||||
| #include <drm/dp/drm_dp_dual_mode_helper.h> | ||||
| #include <drm/drm_print.h> | ||||
| 
 | ||||
| /**
 | ||||
							
								
								
									
										33
									
								
								drivers/gpu/drm/dp/drm_dp_helper_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								drivers/gpu/drm/dp/drm_dp_helper_internal.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| /* SPDX-License-Identifier: MIT */ | ||||
| 
 | ||||
| #ifndef DRM_DP_HELPER_INTERNAL_H | ||||
| #define DRM_DP_HELPER_INTERNAL_H | ||||
| 
 | ||||
| struct drm_dp_aux; | ||||
| 
 | ||||
| #ifdef CONFIG_DRM_DP_AUX_CHARDEV | ||||
| int drm_dp_aux_dev_init(void); | ||||
| void drm_dp_aux_dev_exit(void); | ||||
| int drm_dp_aux_register_devnode(struct drm_dp_aux *aux); | ||||
| void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux); | ||||
| #else | ||||
| static inline int drm_dp_aux_dev_init(void) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline void drm_dp_aux_dev_exit(void) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										22
									
								
								drivers/gpu/drm/dp/drm_dp_helper_mod.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								drivers/gpu/drm/dp/drm_dp_helper_mod.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| // SPDX-License-Identifier: MIT
 | ||||
| 
 | ||||
| #include <linux/module.h> | ||||
| 
 | ||||
| #include "drm_dp_helper_internal.h" | ||||
| 
 | ||||
| MODULE_DESCRIPTION("DRM DisplayPort helper"); | ||||
| MODULE_LICENSE("GPL and additional rights"); | ||||
| 
 | ||||
| static int __init drm_dp_helper_module_init(void) | ||||
| { | ||||
| 	return drm_dp_aux_dev_init(); | ||||
| } | ||||
| 
 | ||||
| static void __exit drm_dp_helper_module_exit(void) | ||||
| { | ||||
| 	/* Call exit functions from specific dp helpers here */ | ||||
| 	drm_dp_aux_dev_exit(); | ||||
| } | ||||
| 
 | ||||
| module_init(drm_dp_helper_module_init); | ||||
| module_exit(drm_dp_helper_module_exit); | ||||
| @ -38,14 +38,14 @@ | ||||
| #include <linux/math64.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <drm/dp/drm_dp_mst_helper.h> | ||||
| #include <drm/drm_atomic.h> | ||||
| #include <drm/drm_atomic_helper.h> | ||||
| #include <drm/drm_dp_mst_helper.h> | ||||
| #include <drm/drm_drv.h> | ||||
| #include <drm/drm_print.h> | ||||
| #include <drm/drm_probe_helper.h> | ||||
| 
 | ||||
| #include "drm_crtc_helper_internal.h" | ||||
| #include "drm_dp_helper_internal.h" | ||||
| #include "drm_dp_mst_topology_internal.h" | ||||
| 
 | ||||
| /**
 | ||||
| @ -4196,7 +4196,7 @@ int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handl | ||||
| 	int ret = 0; | ||||
| 	int sc; | ||||
| 	*handled = false; | ||||
| 	sc = esi[0] & 0x3f; | ||||
| 	sc = DP_GET_SINK_COUNT(esi[0]); | ||||
| 
 | ||||
| 	if (sc != mgr->sink_count) { | ||||
| 		mgr->sink_count = sc; | ||||
| @ -4811,7 +4811,7 @@ static void drm_dp_mst_dump_mstb(struct seq_file *m, | ||||
| 
 | ||||
| 	seq_printf(m, "%smstb - [%p]: num_ports: %d\n", prefix, mstb, mstb->num_ports); | ||||
| 	list_for_each_entry(port, &mstb->ports, next) { | ||||
| 		seq_printf(m, "%sport %d - [%p] (%s - %s): ddps: %d, ldps: %d, sdp: %d/%d, fec: %s, conn: %p\n",  | ||||
| 		seq_printf(m, "%sport %d - [%p] (%s - %s): ddps: %d, ldps: %d, sdp: %d/%d, fec: %s, conn: %p\n", | ||||
| 			   prefix, | ||||
| 			   port->port_num, | ||||
| 			   port, | ||||
| @ -10,7 +10,7 @@ | ||||
| #ifndef _DRM_DP_MST_HELPER_INTERNAL_H_ | ||||
| #define _DRM_DP_MST_HELPER_INTERNAL_H_ | ||||
| 
 | ||||
| #include <drm/drm_dp_mst_helper.h> | ||||
| #include <drm/dp/drm_dp_mst_helper.h> | ||||
| 
 | ||||
| void | ||||
| drm_dp_encode_sideband_req(const struct drm_dp_sideband_msg_req_body *req, | ||||
							
								
								
									
										535
									
								
								drivers/gpu/drm/drm_buddy.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										535
									
								
								drivers/gpu/drm/drm_buddy.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,535 @@ | ||||
| // SPDX-License-Identifier: MIT
 | ||||
| /*
 | ||||
|  * Copyright © 2021 Intel Corporation | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/kmemleak.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/sizes.h> | ||||
| 
 | ||||
| #include <drm/drm_buddy.h> | ||||
| 
 | ||||
| static struct kmem_cache *slab_blocks; | ||||
| 
 | ||||
| static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm, | ||||
| 					       struct drm_buddy_block *parent, | ||||
| 					       unsigned int order, | ||||
| 					       u64 offset) | ||||
| { | ||||
| 	struct drm_buddy_block *block; | ||||
| 
 | ||||
| 	BUG_ON(order > DRM_BUDDY_MAX_ORDER); | ||||
| 
 | ||||
| 	block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL); | ||||
| 	if (!block) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	block->header = offset; | ||||
| 	block->header |= order; | ||||
| 	block->parent = parent; | ||||
| 
 | ||||
| 	BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED); | ||||
| 	return block; | ||||
| } | ||||
| 
 | ||||
| static void drm_block_free(struct drm_buddy *mm, | ||||
| 			   struct drm_buddy_block *block) | ||||
| { | ||||
| 	kmem_cache_free(slab_blocks, block); | ||||
| } | ||||
| 
 | ||||
| static void mark_allocated(struct drm_buddy_block *block) | ||||
| { | ||||
| 	block->header &= ~DRM_BUDDY_HEADER_STATE; | ||||
| 	block->header |= DRM_BUDDY_ALLOCATED; | ||||
| 
 | ||||
| 	list_del(&block->link); | ||||
| } | ||||
| 
 | ||||
| static void mark_free(struct drm_buddy *mm, | ||||
| 		      struct drm_buddy_block *block) | ||||
| { | ||||
| 	block->header &= ~DRM_BUDDY_HEADER_STATE; | ||||
| 	block->header |= DRM_BUDDY_FREE; | ||||
| 
 | ||||
| 	list_add(&block->link, | ||||
| 		 &mm->free_list[drm_buddy_block_order(block)]); | ||||
| } | ||||
| 
 | ||||
| static void mark_split(struct drm_buddy_block *block) | ||||
| { | ||||
| 	block->header &= ~DRM_BUDDY_HEADER_STATE; | ||||
| 	block->header |= DRM_BUDDY_SPLIT; | ||||
| 
 | ||||
| 	list_del(&block->link); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_buddy_init - init memory manager | ||||
|  * | ||||
|  * @mm: DRM buddy manager to initialize | ||||
|  * @size: size in bytes to manage | ||||
|  * @chunk_size: minimum page size in bytes for our allocations | ||||
|  * | ||||
|  * Initializes the memory manager and its resources. | ||||
|  * | ||||
|  * Returns: | ||||
|  * 0 on success, error code on failure. | ||||
|  */ | ||||
| int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) | ||||
| { | ||||
| 	unsigned int i; | ||||
| 	u64 offset; | ||||
| 
 | ||||
| 	if (size < chunk_size) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (chunk_size < PAGE_SIZE) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (!is_power_of_2(chunk_size)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	size = round_down(size, chunk_size); | ||||
| 
 | ||||
| 	mm->size = size; | ||||
| 	mm->avail = size; | ||||
| 	mm->chunk_size = chunk_size; | ||||
| 	mm->max_order = ilog2(size) - ilog2(chunk_size); | ||||
| 
 | ||||
| 	BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER); | ||||
| 
 | ||||
| 	mm->free_list = kmalloc_array(mm->max_order + 1, | ||||
| 				      sizeof(struct list_head), | ||||
| 				      GFP_KERNEL); | ||||
| 	if (!mm->free_list) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	for (i = 0; i <= mm->max_order; ++i) | ||||
| 		INIT_LIST_HEAD(&mm->free_list[i]); | ||||
| 
 | ||||
| 	mm->n_roots = hweight64(size); | ||||
| 
 | ||||
| 	mm->roots = kmalloc_array(mm->n_roots, | ||||
| 				  sizeof(struct drm_buddy_block *), | ||||
| 				  GFP_KERNEL); | ||||
| 	if (!mm->roots) | ||||
| 		goto out_free_list; | ||||
| 
 | ||||
| 	offset = 0; | ||||
| 	i = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Split into power-of-two blocks, in case we are given a size that is | ||||
| 	 * not itself a power-of-two. | ||||
| 	 */ | ||||
| 	do { | ||||
| 		struct drm_buddy_block *root; | ||||
| 		unsigned int order; | ||||
| 		u64 root_size; | ||||
| 
 | ||||
| 		root_size = rounddown_pow_of_two(size); | ||||
| 		order = ilog2(root_size) - ilog2(chunk_size); | ||||
| 
 | ||||
| 		root = drm_block_alloc(mm, NULL, order, offset); | ||||
| 		if (!root) | ||||
| 			goto out_free_roots; | ||||
| 
 | ||||
| 		mark_free(mm, root); | ||||
| 
 | ||||
| 		BUG_ON(i > mm->max_order); | ||||
| 		BUG_ON(drm_buddy_block_size(mm, root) < chunk_size); | ||||
| 
 | ||||
| 		mm->roots[i] = root; | ||||
| 
 | ||||
| 		offset += root_size; | ||||
| 		size -= root_size; | ||||
| 		i++; | ||||
| 	} while (size); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| out_free_roots: | ||||
| 	while (i--) | ||||
| 		drm_block_free(mm, mm->roots[i]); | ||||
| 	kfree(mm->roots); | ||||
| out_free_list: | ||||
| 	kfree(mm->free_list); | ||||
| 	return -ENOMEM; | ||||
| } | ||||
| EXPORT_SYMBOL(drm_buddy_init); | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_buddy_fini - tear down the memory manager | ||||
|  * | ||||
|  * @mm: DRM buddy manager to free | ||||
|  * | ||||
|  * Cleanup memory manager resources and the freelist | ||||
|  */ | ||||
| void drm_buddy_fini(struct drm_buddy *mm) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < mm->n_roots; ++i) { | ||||
| 		WARN_ON(!drm_buddy_block_is_free(mm->roots[i])); | ||||
| 		drm_block_free(mm, mm->roots[i]); | ||||
| 	} | ||||
| 
 | ||||
| 	WARN_ON(mm->avail != mm->size); | ||||
| 
 | ||||
| 	kfree(mm->roots); | ||||
| 	kfree(mm->free_list); | ||||
| } | ||||
| EXPORT_SYMBOL(drm_buddy_fini); | ||||
| 
 | ||||
| static int split_block(struct drm_buddy *mm, | ||||
| 		       struct drm_buddy_block *block) | ||||
| { | ||||
| 	unsigned int block_order = drm_buddy_block_order(block) - 1; | ||||
| 	u64 offset = drm_buddy_block_offset(block); | ||||
| 
 | ||||
| 	BUG_ON(!drm_buddy_block_is_free(block)); | ||||
| 	BUG_ON(!drm_buddy_block_order(block)); | ||||
| 
 | ||||
| 	block->left = drm_block_alloc(mm, block, block_order, offset); | ||||
| 	if (!block->left) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	block->right = drm_block_alloc(mm, block, block_order, | ||||
| 				       offset + (mm->chunk_size << block_order)); | ||||
| 	if (!block->right) { | ||||
| 		drm_block_free(mm, block->left); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	mark_free(mm, block->left); | ||||
| 	mark_free(mm, block->right); | ||||
| 
 | ||||
| 	mark_split(block); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static struct drm_buddy_block * | ||||
| get_buddy(struct drm_buddy_block *block) | ||||
| { | ||||
| 	struct drm_buddy_block *parent; | ||||
| 
 | ||||
| 	parent = block->parent; | ||||
| 	if (!parent) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (parent->left == block) | ||||
| 		return parent->right; | ||||
| 
 | ||||
| 	return parent->left; | ||||
| } | ||||
| 
 | ||||
| static void __drm_buddy_free(struct drm_buddy *mm, | ||||
| 			     struct drm_buddy_block *block) | ||||
| { | ||||
| 	struct drm_buddy_block *parent; | ||||
| 
 | ||||
| 	while ((parent = block->parent)) { | ||||
| 		struct drm_buddy_block *buddy; | ||||
| 
 | ||||
| 		buddy = get_buddy(block); | ||||
| 
 | ||||
| 		if (!drm_buddy_block_is_free(buddy)) | ||||
| 			break; | ||||
| 
 | ||||
| 		list_del(&buddy->link); | ||||
| 
 | ||||
| 		drm_block_free(mm, block); | ||||
| 		drm_block_free(mm, buddy); | ||||
| 
 | ||||
| 		block = parent; | ||||
| 	} | ||||
| 
 | ||||
| 	mark_free(mm, block); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_buddy_free_block - free a block | ||||
|  * | ||||
|  * @mm: DRM buddy manager | ||||
|  * @block: block to be freed | ||||
|  */ | ||||
| void drm_buddy_free_block(struct drm_buddy *mm, | ||||
| 			  struct drm_buddy_block *block) | ||||
| { | ||||
| 	BUG_ON(!drm_buddy_block_is_allocated(block)); | ||||
| 	mm->avail += drm_buddy_block_size(mm, block); | ||||
| 	__drm_buddy_free(mm, block); | ||||
| } | ||||
| EXPORT_SYMBOL(drm_buddy_free_block); | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_buddy_free_list - free blocks | ||||
|  * | ||||
|  * @mm: DRM buddy manager | ||||
|  * @objects: input list head to free blocks | ||||
|  */ | ||||
| void drm_buddy_free_list(struct drm_buddy *mm, struct list_head *objects) | ||||
| { | ||||
| 	struct drm_buddy_block *block, *on; | ||||
| 
 | ||||
| 	list_for_each_entry_safe(block, on, objects, link) { | ||||
| 		drm_buddy_free_block(mm, block); | ||||
| 		cond_resched(); | ||||
| 	} | ||||
| 	INIT_LIST_HEAD(objects); | ||||
| } | ||||
| EXPORT_SYMBOL(drm_buddy_free_list); | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_buddy_alloc_blocks - allocate power-of-two blocks | ||||
|  * | ||||
|  * @mm: DRM buddy manager to allocate from | ||||
|  * @order: size of the allocation | ||||
|  * | ||||
|  * The order value here translates to: | ||||
|  * | ||||
|  * 0 = 2^0 * mm->chunk_size | ||||
|  * 1 = 2^1 * mm->chunk_size | ||||
|  * 2 = 2^2 * mm->chunk_size | ||||
|  * | ||||
|  * Returns: | ||||
|  * allocated ptr to the &drm_buddy_block on success | ||||
|  */ | ||||
| struct drm_buddy_block * | ||||
| drm_buddy_alloc_blocks(struct drm_buddy *mm, unsigned int order) | ||||
| { | ||||
| 	struct drm_buddy_block *block = NULL; | ||||
| 	unsigned int i; | ||||
| 	int err; | ||||
| 
 | ||||
| 	for (i = order; i <= mm->max_order; ++i) { | ||||
| 		block = list_first_entry_or_null(&mm->free_list[i], | ||||
| 						 struct drm_buddy_block, | ||||
| 						 link); | ||||
| 		if (block) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!block) | ||||
| 		return ERR_PTR(-ENOSPC); | ||||
| 
 | ||||
| 	BUG_ON(!drm_buddy_block_is_free(block)); | ||||
| 
 | ||||
| 	while (i != order) { | ||||
| 		err = split_block(mm, block); | ||||
| 		if (unlikely(err)) | ||||
| 			goto out_free; | ||||
| 
 | ||||
| 		/* Go low */ | ||||
| 		block = block->left; | ||||
| 		i--; | ||||
| 	} | ||||
| 
 | ||||
| 	mark_allocated(block); | ||||
| 	mm->avail -= drm_buddy_block_size(mm, block); | ||||
| 	kmemleak_update_trace(block); | ||||
| 	return block; | ||||
| 
 | ||||
| out_free: | ||||
| 	if (i != order) | ||||
| 		__drm_buddy_free(mm, block); | ||||
| 	return ERR_PTR(err); | ||||
| } | ||||
| EXPORT_SYMBOL(drm_buddy_alloc_blocks); | ||||
| 
 | ||||
| static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) | ||||
| { | ||||
| 	return s1 <= e2 && e1 >= s2; | ||||
| } | ||||
| 
 | ||||
| static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) | ||||
| { | ||||
| 	return s1 <= s2 && e1 >= e2; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_buddy_alloc_range - allocate range | ||||
|  * | ||||
|  * @mm: DRM buddy manager to allocate from | ||||
|  * @blocks: output list head to add allocated blocks | ||||
|  * @start: start of the allowed range for this block | ||||
|  * @size: size of the allocation | ||||
|  * | ||||
|  * Intended for pre-allocating portions of the address space, for example to | ||||
|  * reserve a block for the initial framebuffer or similar, hence the expectation | ||||
|  * here is that drm_buddy_alloc_blocks() is still the main vehicle for | ||||
|  * allocations, so if that's not the case then the drm_mm range allocator is | ||||
|  * probably a much better fit, and so you should probably go use that instead. | ||||
|  * | ||||
|  * Note that it's safe to chain together multiple alloc_ranges | ||||
|  * with the same blocks list | ||||
|  * | ||||
|  * Returns: | ||||
|  * 0 on success, error code on failure. | ||||
|  */ | ||||
| int drm_buddy_alloc_range(struct drm_buddy *mm, | ||||
| 			  struct list_head *blocks, | ||||
| 			  u64 start, u64 size) | ||||
| { | ||||
| 	struct drm_buddy_block *block; | ||||
| 	struct drm_buddy_block *buddy; | ||||
| 	LIST_HEAD(allocated); | ||||
| 	LIST_HEAD(dfs); | ||||
| 	u64 end; | ||||
| 	int err; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (size < mm->chunk_size) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (!IS_ALIGNED(size | start, mm->chunk_size)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (range_overflows(start, size, mm->size)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	for (i = 0; i < mm->n_roots; ++i) | ||||
| 		list_add_tail(&mm->roots[i]->tmp_link, &dfs); | ||||
| 
 | ||||
| 	end = start + size - 1; | ||||
| 
 | ||||
| 	do { | ||||
| 		u64 block_start; | ||||
| 		u64 block_end; | ||||
| 
 | ||||
| 		block = list_first_entry_or_null(&dfs, | ||||
| 						 struct drm_buddy_block, | ||||
| 						 tmp_link); | ||||
| 		if (!block) | ||||
| 			break; | ||||
| 
 | ||||
| 		list_del(&block->tmp_link); | ||||
| 
 | ||||
| 		block_start = drm_buddy_block_offset(block); | ||||
| 		block_end = block_start + drm_buddy_block_size(mm, block) - 1; | ||||
| 
 | ||||
| 		if (!overlaps(start, end, block_start, block_end)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (drm_buddy_block_is_allocated(block)) { | ||||
| 			err = -ENOSPC; | ||||
| 			goto err_free; | ||||
| 		} | ||||
| 
 | ||||
| 		if (contains(start, end, block_start, block_end)) { | ||||
| 			if (!drm_buddy_block_is_free(block)) { | ||||
| 				err = -ENOSPC; | ||||
| 				goto err_free; | ||||
| 			} | ||||
| 
 | ||||
| 			mark_allocated(block); | ||||
| 			mm->avail -= drm_buddy_block_size(mm, block); | ||||
| 			list_add_tail(&block->link, &allocated); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!drm_buddy_block_is_split(block)) { | ||||
| 			err = split_block(mm, block); | ||||
| 			if (unlikely(err)) | ||||
| 				goto err_undo; | ||||
| 		} | ||||
| 
 | ||||
| 		list_add(&block->right->tmp_link, &dfs); | ||||
| 		list_add(&block->left->tmp_link, &dfs); | ||||
| 	} while (1); | ||||
| 
 | ||||
| 	list_splice_tail(&allocated, blocks); | ||||
| 	return 0; | ||||
| 
 | ||||
| err_undo: | ||||
| 	/*
 | ||||
| 	 * We really don't want to leave around a bunch of split blocks, since | ||||
| 	 * bigger is better, so make sure we merge everything back before we | ||||
| 	 * free the allocated blocks. | ||||
| 	 */ | ||||
| 	buddy = get_buddy(block); | ||||
| 	if (buddy && | ||||
| 	    (drm_buddy_block_is_free(block) && | ||||
| 	     drm_buddy_block_is_free(buddy))) | ||||
| 		__drm_buddy_free(mm, block); | ||||
| 
 | ||||
| err_free: | ||||
| 	drm_buddy_free_list(mm, &allocated); | ||||
| 	return err; | ||||
| } | ||||
| EXPORT_SYMBOL(drm_buddy_alloc_range); | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_buddy_block_print - print block information | ||||
|  * | ||||
|  * @mm: DRM buddy manager | ||||
|  * @block: DRM buddy block | ||||
|  * @p: DRM printer to use | ||||
|  */ | ||||
| void drm_buddy_block_print(struct drm_buddy *mm, | ||||
| 			   struct drm_buddy_block *block, | ||||
| 			   struct drm_printer *p) | ||||
| { | ||||
| 	u64 start = drm_buddy_block_offset(block); | ||||
| 	u64 size = drm_buddy_block_size(mm, block); | ||||
| 
 | ||||
| 	drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size); | ||||
| } | ||||
| EXPORT_SYMBOL(drm_buddy_block_print); | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_buddy_print - print allocator state | ||||
|  * | ||||
|  * @mm: DRM buddy manager | ||||
|  * @p: DRM printer to use | ||||
|  */ | ||||
| void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) | ||||
| { | ||||
| 	int order; | ||||
| 
 | ||||
| 	drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n", | ||||
| 		   mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20); | ||||
| 
 | ||||
| 	for (order = mm->max_order; order >= 0; order--) { | ||||
| 		struct drm_buddy_block *block; | ||||
| 		u64 count = 0, free; | ||||
| 
 | ||||
| 		list_for_each_entry(block, &mm->free_list[order], link) { | ||||
| 			BUG_ON(!drm_buddy_block_is_free(block)); | ||||
| 			count++; | ||||
| 		} | ||||
| 
 | ||||
| 		drm_printf(p, "order-%d ", order); | ||||
| 
 | ||||
| 		free = count * (mm->chunk_size << order); | ||||
| 		if (free < SZ_1M) | ||||
| 			drm_printf(p, "free: %lluKiB", free >> 10); | ||||
| 		else | ||||
| 			drm_printf(p, "free: %lluMiB", free >> 20); | ||||
| 
 | ||||
| 		drm_printf(p, ", pages: %llu\n", count); | ||||
| 	} | ||||
| } | ||||
| EXPORT_SYMBOL(drm_buddy_print); | ||||
| 
 | ||||
| static void drm_buddy_module_exit(void) | ||||
| { | ||||
| 	kmem_cache_destroy(slab_blocks); | ||||
| } | ||||
| 
 | ||||
| static int __init drm_buddy_module_init(void) | ||||
| { | ||||
| 	slab_blocks = KMEM_CACHE(drm_buddy_block, 0); | ||||
| 	if (!slab_blocks) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| module_init(drm_buddy_module_init); | ||||
| module_exit(drm_buddy_module_exit); | ||||
| 
 | ||||
| MODULE_DESCRIPTION("DRM Buddy Allocator"); | ||||
| MODULE_LICENSE("Dual MIT/GPL"); | ||||
| @ -82,6 +82,10 @@ | ||||
|  *	driver boot-up state too. Drivers can access this blob through | ||||
|  *	&drm_crtc_state.gamma_lut. | ||||
|  * | ||||
|  *	Note that for mostly historical reasons stemming from Xorg heritage, | ||||
|  *	this is also used to store the color map (also sometimes color lut, CLUT | ||||
|  *	or color palette) for indexed formats like DRM_FORMAT_C8. | ||||
|  * | ||||
|  * “GAMMA_LUT_SIZE”: | ||||
|  *	Unsigned range property to give the size of the lookup table to be set | ||||
|  *	on the GAMMA_LUT property (the size depends on the underlying hardware). | ||||
|  | ||||
| @ -28,36 +28,9 @@ | ||||
| 
 | ||||
| #include <drm/drm_connector.h> | ||||
| #include <drm/drm_crtc.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/drm_encoder.h> | ||||
| #include <drm/drm_modes.h> | ||||
| 
 | ||||
| /* drm_dp_aux_dev.c */ | ||||
| #ifdef CONFIG_DRM_DP_AUX_CHARDEV | ||||
| int drm_dp_aux_dev_init(void); | ||||
| void drm_dp_aux_dev_exit(void); | ||||
| int drm_dp_aux_register_devnode(struct drm_dp_aux *aux); | ||||
| void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux); | ||||
| #else | ||||
| static inline int drm_dp_aux_dev_init(void) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline void drm_dp_aux_dev_exit(void) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /* drm_probe_helper.c */ | ||||
| enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc, | ||||
| 					 const struct drm_display_mode *mode); | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
| #include <linux/errno.h> | ||||
| #include <linux/byteorder/generic.h> | ||||
| #include <drm/drm_print.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_dsc.h> | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -93,6 +93,8 @@ static int oui(u8 first, u8 second, u8 third) | ||||
| /* Non desktop display (i.e. HMD) */ | ||||
| #define EDID_QUIRK_NON_DESKTOP			(1 << 12) | ||||
| 
 | ||||
| #define MICROSOFT_IEEE_OUI	0xca125c | ||||
| 
 | ||||
| struct detailed_mode_closure { | ||||
| 	struct drm_connector *connector; | ||||
| 	struct edid *edid; | ||||
| @ -212,9 +214,7 @@ static const struct edid_quirk { | ||||
| 
 | ||||
| 	/* Windows Mixed Reality Headsets */ | ||||
| 	EDID_QUIRK('A', 'C', 'R', 0x7fce, EDID_QUIRK_NON_DESKTOP), | ||||
| 	EDID_QUIRK('H', 'P', 'N', 0x3515, EDID_QUIRK_NON_DESKTOP), | ||||
| 	EDID_QUIRK('L', 'E', 'N', 0x0408, EDID_QUIRK_NON_DESKTOP), | ||||
| 	EDID_QUIRK('L', 'E', 'N', 0xb800, EDID_QUIRK_NON_DESKTOP), | ||||
| 	EDID_QUIRK('F', 'U', 'J', 0x1970, EDID_QUIRK_NON_DESKTOP), | ||||
| 	EDID_QUIRK('D', 'E', 'L', 0x7fce, EDID_QUIRK_NON_DESKTOP), | ||||
| 	EDID_QUIRK('S', 'E', 'C', 0x144a, EDID_QUIRK_NON_DESKTOP), | ||||
| @ -3776,7 +3776,7 @@ static int do_y420vdb_modes(struct drm_connector *connector, | ||||
| 	} | ||||
| 
 | ||||
| 	if (modes > 0) | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB420; | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; | ||||
| 	return modes; | ||||
| } | ||||
| 
 | ||||
| @ -4222,6 +4222,17 @@ static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) | ||||
| 	return oui(db[3], db[2], db[1]) == HDMI_FORUM_IEEE_OUI; | ||||
| } | ||||
| 
 | ||||
| static bool cea_db_is_microsoft_vsdb(const u8 *db) | ||||
| { | ||||
| 	if (cea_db_tag(db) != VENDOR_BLOCK) | ||||
| 		return false; | ||||
| 
 | ||||
| 	if (cea_db_payload_len(db) != 21) | ||||
| 		return false; | ||||
| 
 | ||||
| 	return oui(db[3], db[2], db[1]) == MICROSOFT_IEEE_OUI; | ||||
| } | ||||
| 
 | ||||
| static bool cea_db_is_vcdb(const u8 *db) | ||||
| { | ||||
| 	if (cea_db_tag(db) != USE_EXTENDED_TAG) | ||||
| @ -4279,7 +4290,7 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, | ||||
| 	if (map_len == 0) { | ||||
| 		/* All CEA modes support ycbcr420 sampling also.*/ | ||||
| 		hdmi->y420_cmdb_map = U64_MAX; | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB420; | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| @ -4302,7 +4313,7 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, | ||||
| 		map |= (u64)db[2 + count] << (8 * count); | ||||
| 
 | ||||
| 	if (map) | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB420; | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; | ||||
| 
 | ||||
| 	hdmi->y420_cmdb_map = map; | ||||
| } | ||||
| @ -5075,21 +5086,21 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, | ||||
| 
 | ||||
| 	if (hdmi[6] & DRM_EDID_HDMI_DC_30) { | ||||
| 		dc_bpc = 10; | ||||
| 		info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30; | ||||
| 		info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_30; | ||||
| 		DRM_DEBUG("%s: HDMI sink does deep color 30.\n", | ||||
| 			  connector->name); | ||||
| 	} | ||||
| 
 | ||||
| 	if (hdmi[6] & DRM_EDID_HDMI_DC_36) { | ||||
| 		dc_bpc = 12; | ||||
| 		info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36; | ||||
| 		info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_36; | ||||
| 		DRM_DEBUG("%s: HDMI sink does deep color 36.\n", | ||||
| 			  connector->name); | ||||
| 	} | ||||
| 
 | ||||
| 	if (hdmi[6] & DRM_EDID_HDMI_DC_48) { | ||||
| 		dc_bpc = 16; | ||||
| 		info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48; | ||||
| 		info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_48; | ||||
| 		DRM_DEBUG("%s: HDMI sink does deep color 48.\n", | ||||
| 			  connector->name); | ||||
| 	} | ||||
| @ -5104,16 +5115,9 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, | ||||
| 		  connector->name, dc_bpc); | ||||
| 	info->bpc = dc_bpc; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Deep color support mandates RGB444 support for all video | ||||
| 	 * modes and forbids YCRCB422 support for all video modes per | ||||
| 	 * HDMI 1.3 spec. | ||||
| 	 */ | ||||
| 	info->color_formats = DRM_COLOR_FORMAT_RGB444; | ||||
| 
 | ||||
| 	/* YCRCB444 is optional according to spec. */ | ||||
| 	if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; | ||||
| 		info->edid_hdmi_ycbcr444_dc_modes = info->edid_hdmi_rgb444_dc_modes; | ||||
| 		DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", | ||||
| 			  connector->name); | ||||
| 	} | ||||
| @ -5149,6 +5153,25 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db) | ||||
| 	drm_parse_hdmi_deep_color_info(connector, db); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * See EDID extension for head-mounted and specialized monitors, specified at: | ||||
|  * https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
 | ||||
|  */ | ||||
| static void drm_parse_microsoft_vsdb(struct drm_connector *connector, | ||||
| 				     const u8 *db) | ||||
| { | ||||
| 	struct drm_display_info *info = &connector->display_info; | ||||
| 	u8 version = db[4]; | ||||
| 	bool desktop_usage = db[5] & BIT(6); | ||||
| 
 | ||||
| 	/* Version 1 and 2 for HMDs, version 3 flags desktop usage explicitly */ | ||||
| 	if (version == 1 || version == 2 || (version == 3 && !desktop_usage)) | ||||
| 		info->non_desktop = true; | ||||
| 
 | ||||
| 	drm_dbg_kms(connector->dev, "HMD or specialized display VSDB version %u: 0x%02x\n", | ||||
| 		    version, db[5]); | ||||
| } | ||||
| 
 | ||||
| static void drm_parse_cea_ext(struct drm_connector *connector, | ||||
| 			      const struct edid *edid) | ||||
| { | ||||
| @ -5165,9 +5188,9 @@ static void drm_parse_cea_ext(struct drm_connector *connector, | ||||
| 	/* The existence of a CEA block should imply RGB support */ | ||||
| 	info->color_formats = DRM_COLOR_FORMAT_RGB444; | ||||
| 	if (edid_ext[3] & EDID_CEA_YCRCB444) | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; | ||||
| 	if (edid_ext[3] & EDID_CEA_YCRCB422) | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; | ||||
| 
 | ||||
| 	if (cea_db_offsets(edid_ext, &start, &end)) | ||||
| 		return; | ||||
| @ -5179,6 +5202,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, | ||||
| 			drm_parse_hdmi_vsdb_video(connector, db); | ||||
| 		if (cea_db_is_hdmi_forum_vsdb(db)) | ||||
| 			drm_parse_hdmi_forum_vsdb(connector, db); | ||||
| 		if (cea_db_is_microsoft_vsdb(db)) | ||||
| 			drm_parse_microsoft_vsdb(connector, db); | ||||
| 		if (cea_db_is_y420cmdb(db)) | ||||
| 			drm_parse_y420cmdb_bitmap(connector, db); | ||||
| 		if (cea_db_is_vcdb(db)) | ||||
| @ -5333,17 +5358,13 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi | ||||
| 	info->width_mm = edid->width_cm * 10; | ||||
| 	info->height_mm = edid->height_cm * 10; | ||||
| 
 | ||||
| 	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP); | ||||
| 
 | ||||
| 	drm_get_monitor_range(connector, edid); | ||||
| 
 | ||||
| 	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop); | ||||
| 
 | ||||
| 	if (edid->revision < 3) | ||||
| 		return quirks; | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) | ||||
| 		return quirks; | ||||
| 		goto out; | ||||
| 
 | ||||
| 	drm_parse_cea_ext(connector, edid); | ||||
| 
 | ||||
| @ -5363,7 +5384,7 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi | ||||
| 
 | ||||
| 	/* Only defined for 1.4 with digital displays */ | ||||
| 	if (edid->revision < 4) | ||||
| 		return quirks; | ||||
| 		goto out; | ||||
| 
 | ||||
| 	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) { | ||||
| 	case DRM_EDID_DIGITAL_DEPTH_6: | ||||
| @ -5395,17 +5416,25 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi | ||||
| 
 | ||||
| 	info->color_formats |= DRM_COLOR_FORMAT_RGB444; | ||||
| 	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; | ||||
| 	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; | ||||
| 		info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; | ||||
| 
 | ||||
| 	drm_update_mso(connector, edid); | ||||
| 
 | ||||
| out: | ||||
| 	if (quirks & EDID_QUIRK_NON_DESKTOP) { | ||||
| 		drm_dbg_kms(connector->dev, "Non-desktop display%s\n", | ||||
| 			    info->non_desktop ? " (redundant quirk)" : ""); | ||||
| 		info->non_desktop = true; | ||||
| 	} | ||||
| 
 | ||||
| 	return quirks; | ||||
| } | ||||
| 
 | ||||
| static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev, | ||||
| 							    struct displayid_detailed_timings_1 *timings) | ||||
| 							    struct displayid_detailed_timings_1 *timings, | ||||
| 							    bool type_7) | ||||
| { | ||||
| 	struct drm_display_mode *mode; | ||||
| 	unsigned pixel_clock = (timings->pixel_clock[0] | | ||||
| @ -5426,7 +5455,8 @@ static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *d | ||||
| 	if (!mode) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	mode->clock = pixel_clock * 10; | ||||
| 	/* resolution is kHz for type VII, and 10 kHz for type I */ | ||||
| 	mode->clock = type_7 ? pixel_clock : pixel_clock * 10; | ||||
| 	mode->hdisplay = hactive; | ||||
| 	mode->hsync_start = mode->hdisplay + hsync; | ||||
| 	mode->hsync_end = mode->hsync_start + hsync_width; | ||||
| @ -5457,6 +5487,7 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector, | ||||
| 	int num_timings; | ||||
| 	struct drm_display_mode *newmode; | ||||
| 	int num_modes = 0; | ||||
| 	bool type_7 = block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING; | ||||
| 	/* blocks must be multiple of 20 bytes length */ | ||||
| 	if (block->num_bytes % 20) | ||||
| 		return 0; | ||||
| @ -5465,7 +5496,7 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector, | ||||
| 	for (i = 0; i < num_timings; i++) { | ||||
| 		struct displayid_detailed_timings_1 *timings = &det->timings[i]; | ||||
| 
 | ||||
| 		newmode = drm_mode_displayid_detailed(connector->dev, timings); | ||||
| 		newmode = drm_mode_displayid_detailed(connector->dev, timings, type_7); | ||||
| 		if (!newmode) | ||||
| 			continue; | ||||
| 
 | ||||
| @ -5484,7 +5515,8 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, | ||||
| 
 | ||||
| 	displayid_iter_edid_begin(edid, &iter); | ||||
| 	displayid_iter_for_each(block, &iter) { | ||||
| 		if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING) | ||||
| 		if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING || | ||||
| 		    block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING) | ||||
| 			num_modes += add_displayid_detailed_1_modes(connector, block); | ||||
| 	} | ||||
| 	displayid_iter_end(&iter); | ||||
| @ -5652,7 +5684,7 @@ static bool is_hdmi2_sink(const struct drm_connector *connector) | ||||
| 		return true; | ||||
| 
 | ||||
| 	return connector->display_info.hdmi.scdc.supported || | ||||
| 		connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420; | ||||
| 		connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR420; | ||||
| } | ||||
| 
 | ||||
| static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf) | ||||
| @ -5891,13 +5923,13 @@ static const u32 hdmi_colorimetry_val[] = { | ||||
| #undef ACE | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_hdmi_avi_infoframe_colorspace() - fill the HDMI AVI infoframe | ||||
|  *                                       colorspace information | ||||
|  * drm_hdmi_avi_infoframe_colorimetry() - fill the HDMI AVI infoframe | ||||
|  *                                       colorimetry information | ||||
|  * @frame: HDMI AVI infoframe | ||||
|  * @conn_state: connector state | ||||
|  */ | ||||
| void | ||||
| drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, | ||||
| drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, | ||||
| 				  const struct drm_connector_state *conn_state) | ||||
| { | ||||
| 	u32 colorimetry_val; | ||||
| @ -5916,7 +5948,7 @@ drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, | ||||
| 	frame->extended_colorimetry = (colorimetry_val >> 2) & | ||||
| 					EXTENDED_COLORIMETRY_MASK; | ||||
| } | ||||
| EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorspace); | ||||
| EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorimetry); | ||||
| 
 | ||||
| /**
 | ||||
|  * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe | ||||
|  | ||||
| @ -61,17 +61,3 @@ MODULE_PARM_DESC(edid_firmware, | ||||
| 		 "DEPRECATED. Use drm.edid_firmware module parameter instead."); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| static int __init drm_kms_helper_init(void) | ||||
| { | ||||
| 	return drm_dp_aux_dev_init(); | ||||
| } | ||||
| 
 | ||||
| static void __exit drm_kms_helper_exit(void) | ||||
| { | ||||
| 	/* Call exit functions from specific kms helpers here */ | ||||
| 	drm_dp_aux_dev_exit(); | ||||
| } | ||||
| 
 | ||||
| module_init(drm_kms_helper_init); | ||||
| module_exit(drm_kms_helper_exit); | ||||
|  | ||||
| @ -202,17 +202,13 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane | ||||
| 
 | ||||
| 	memcpy(formats_ptr(blob_data), plane->format_types, formats_size); | ||||
| 
 | ||||
| 	/* If we can't determine support, just bail */ | ||||
| 	if (!plane->funcs->format_mod_supported) | ||||
| 		goto done; | ||||
| 
 | ||||
| 	mod = modifiers_ptr(blob_data); | ||||
| 	for (i = 0; i < plane->modifier_count; i++) { | ||||
| 		for (j = 0; j < plane->format_count; j++) { | ||||
| 			if (plane->funcs->format_mod_supported(plane, | ||||
| 			if (!plane->funcs->format_mod_supported || | ||||
| 			    plane->funcs->format_mod_supported(plane, | ||||
| 							       plane->format_types[j], | ||||
| 							       plane->modifiers[i])) { | ||||
| 
 | ||||
| 				mod->formats |= 1ULL << j; | ||||
| 			} | ||||
| 		} | ||||
| @ -223,7 +219,6 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane | ||||
| 		mod++; | ||||
| 	} | ||||
| 
 | ||||
| done: | ||||
| 	drm_object_attach_property(&plane->base, config->modifiers_property, | ||||
| 				   blob->base.id); | ||||
| 
 | ||||
|  | ||||
| @ -387,7 +387,8 @@ static void drm_privacy_screen_device_release(struct device *dev) | ||||
|  * * An ERR_PTR(errno) on failure. | ||||
|  */ | ||||
| struct drm_privacy_screen *drm_privacy_screen_register( | ||||
| 	struct device *parent, const struct drm_privacy_screen_ops *ops) | ||||
| 	struct device *parent, const struct drm_privacy_screen_ops *ops, | ||||
| 	void *data) | ||||
| { | ||||
| 	struct drm_privacy_screen *priv; | ||||
| 	int ret; | ||||
| @ -404,6 +405,7 @@ struct drm_privacy_screen *drm_privacy_screen_register( | ||||
| 	priv->dev.parent = parent; | ||||
| 	priv->dev.release = drm_privacy_screen_device_release; | ||||
| 	dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent)); | ||||
| 	priv->drvdata = data; | ||||
| 	priv->ops = ops; | ||||
| 
 | ||||
| 	priv->ops->get_hw_state(priv); | ||||
| @ -439,6 +441,7 @@ void drm_privacy_screen_unregister(struct drm_privacy_screen *priv) | ||||
| 	mutex_unlock(&drm_privacy_screen_devs_lock); | ||||
| 
 | ||||
| 	mutex_lock(&priv->lock); | ||||
| 	priv->drvdata = NULL; | ||||
| 	priv->ops = NULL; | ||||
| 	mutex_unlock(&priv->lock); | ||||
| 
 | ||||
|  | ||||
| @ -50,6 +50,13 @@ static bool __init detect_thinkpad_privacy_screen(void) | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_CHROMEOS_PRIVACY_SCREEN) | ||||
| static bool __init detect_chromeos_privacy_screen(void) | ||||
| { | ||||
| 	return acpi_dev_present("GOOG0010", NULL, -1); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static const struct arch_init_data arch_init_data[] __initconst = { | ||||
| #if IS_ENABLED(CONFIG_THINKPAD_ACPI) | ||||
| 	{ | ||||
| @ -61,6 +68,16 @@ static const struct arch_init_data arch_init_data[] __initconst = { | ||||
| 		.detect = detect_thinkpad_privacy_screen, | ||||
| 	}, | ||||
| #endif | ||||
| #if IS_ENABLED(CONFIG_CHROMEOS_PRIVACY_SCREEN) | ||||
| 	{ | ||||
| 		.lookup = { | ||||
| 			.dev_id = NULL, | ||||
| 			.con_id = NULL, | ||||
| 			.provider = "privacy_screen-GOOG0010:00", | ||||
| 		}, | ||||
| 		.detect = detect_chromeos_privacy_screen, | ||||
| 	}, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| void __init drm_privacy_screen_lookup_init(void) | ||||
|  | ||||
| @ -189,8 +189,7 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (bo->flags & ETNA_SUBMIT_BO_WRITE) { | ||||
| 			ret = dma_resv_get_fences(robj, NULL, | ||||
| 						  &bo->nr_shared, | ||||
| 			ret = dma_resv_get_fences(robj, true, &bo->nr_shared, | ||||
| 						  &bo->shared); | ||||
| 			if (ret) | ||||
| 				return ret; | ||||
|  | ||||
| @ -66,6 +66,7 @@ config DRM_EXYNOS_DP | ||||
| 	bool "Exynos specific extensions for Analogix DP driver" | ||||
| 	depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON | ||||
| 	select DRM_ANALOGIX_DP | ||||
| 	select DRM_DP_HELPER | ||||
| 	default DRM_EXYNOS | ||||
| 	select DRM_PANEL | ||||
| 	help | ||||
|  | ||||
| @ -258,6 +258,7 @@ struct exynos_dsi { | ||||
| 	struct list_head bridge_chain; | ||||
| 	struct drm_bridge *out_bridge; | ||||
| 	struct device *dev; | ||||
| 	struct drm_display_mode mode; | ||||
| 
 | ||||
| 	void __iomem *reg_base; | ||||
| 	struct phy *phy; | ||||
| @ -881,7 +882,7 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) | ||||
| 
 | ||||
| static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi) | ||||
| { | ||||
| 	struct drm_display_mode *m = &dsi->encoder.crtc->state->adjusted_mode; | ||||
| 	struct drm_display_mode *m = &dsi->mode; | ||||
| 	unsigned int num_bits_resol = dsi->driver_data->num_bits_resol; | ||||
| 	u32 reg; | ||||
| 
 | ||||
| @ -1446,6 +1447,15 @@ static void exynos_dsi_disable(struct drm_encoder *encoder) | ||||
| 	pm_runtime_put_sync(dsi->dev); | ||||
| } | ||||
| 
 | ||||
| static void exynos_dsi_mode_set(struct drm_encoder *encoder, | ||||
| 				struct drm_display_mode *mode, | ||||
| 				struct drm_display_mode *adjusted_mode) | ||||
| { | ||||
| 	struct exynos_dsi *dsi = encoder_to_dsi(encoder); | ||||
| 
 | ||||
| 	drm_mode_copy(&dsi->mode, adjusted_mode); | ||||
| } | ||||
| 
 | ||||
| static enum drm_connector_status | ||||
| exynos_dsi_detect(struct drm_connector *connector, bool force) | ||||
| { | ||||
| @ -1513,6 +1523,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) | ||||
| static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = { | ||||
| 	.enable = exynos_dsi_enable, | ||||
| 	.disable = exynos_dsi_disable, | ||||
| 	.mode_set = exynos_dsi_mode_set, | ||||
| }; | ||||
| 
 | ||||
| MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); | ||||
|  | ||||
| @ -31,7 +31,7 @@ | ||||
| 
 | ||||
| #include <drm/drm_crtc.h> | ||||
| #include <drm/drm_crtc_helper.h> | ||||
| #include <drm/drm_dp_helper.h> | ||||
| #include <drm/dp/drm_dp_helper.h> | ||||
| #include <drm/drm_simple_kms_helper.h> | ||||
| 
 | ||||
| #include "gma_display.h" | ||||
| @ -82,7 +82,6 @@ i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading) | ||||
| { | ||||
| 	struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; | ||||
| 	int mode = MODE_I2C_START; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (reading) | ||||
| 		mode |= MODE_I2C_READ; | ||||
| @ -90,8 +89,7 @@ i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading) | ||||
| 		mode |= MODE_I2C_WRITE; | ||||
| 	algo_data->address = address; | ||||
| 	algo_data->running = true; | ||||
| 	ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); | ||||
| 	return ret; | ||||
| 	return i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -122,13 +120,11 @@ static int | ||||
| i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte) | ||||
| { | ||||
| 	struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!algo_data->running) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL); | ||||
| 	return ret; | ||||
| 	return i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -139,13 +135,11 @@ static int | ||||
| i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret) | ||||
| { | ||||
| 	struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!algo_data->running) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret); | ||||
| 	return ret; | ||||
| 	return i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user