[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>
Unified · Split
| @@ -39,6 +39,7 @@ properties: · 38 unmodified lines | ||
| 39 | 39 | - const: lvds-encoder # Generic LVDS encoder compatible fallback |
| 40 | 40 | - items: |
| 41 | 41 | - enum: |
| 42 | + - ti,ds90cf364a # For the DS90CF364A FPD-Link LVDS Receiver | |
| 42 | 43 | - ti,ds90cf384a # For the DS90CF384A FPD-Link LVDS Receiver |
| 43 | 44 | - const: lvds-decoder # Generic LVDS decoders compatible fallback |
| 44 | 45 | - enum: |
| @@ -32,6 +32,9 @@ properties: · 31 unmodified lines | ||
| 32 | 32 | maxItems: 1 |
| 33 | 33 | description: GPIO specifier for bridge_en pin (active high). |
| 34 | 34 | |
| 35 | + vcc-supply: | |
| 36 | + description: A 1.8V power supply (see regulator/regulator.yaml). | |
| 37 | + | |
| 35 | 38 | ports: |
| 36 | 39 | $ref: /schemas/graph.yaml#/properties/ports |
| 37 | 40 | |
| @@ -91,7 +94,6 @@ properties: · 53 unmodified lines | ||
| 91 | 94 | required: |
| 92 | 95 | - compatible |
| 93 | 96 | - reg |
| 94 | − - enable-gpios | |
| 95 | 97 | - ports |
| 96 | 98 | |
| 97 | 99 | allOf: |
| @@ -133,6 +135,7 @@ examples: · 35 unmodified lines | ||
| 133 | 135 | reg = <0x2d>; |
| 134 | 136 | |
| 135 | 137 | enable-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; |
| 138 | + vcc-supply = <®_sn65dsi83_1v8>; | |
| 136 | 139 | |
| 137 | 140 | ports { |
| 138 | 141 | #address-cells = <1>; |
| @@ -222,6 +222,8 @@ properties: · 221 unmodified lines | ||
| 222 | 222 | - logictechno,lttd800480070-l6wh-rt |
| 223 | 223 | # Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel |
| 224 | 224 | - mitsubishi,aa070mc01-ca1 |
| 225 | + # Multi-Inno Technology Co.,Ltd MI0700S4T-6 7" 800x480 TFT Resistive Touch Module | |
| 226 | + - multi-inno,mi0700s4t-6 | |
| 225 | 227 | # Multi-Inno Technology Co.,Ltd MI1010AIT-1CP 10.1" 1280x800 LVDS IPS Cap Touch Mod. |
| 226 | 228 | - multi-inno,mi1010ait-1cp |
| 227 | 229 | # NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel |
| @@ -4,7 +4,12 @@ · 3 unmodified lines | ||
| 4 | 4 | $id: http://devicetree.org/schemas/display/panel/sony,acx424akp.yaml# |
| 5 | 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# |
| 6 | 6 | |
| 7 | −title: Sony ACX424AKP 4" 480x864 AMOLED panel | |
| 7 | +title: Sony ACX424AKP/ACX424AKM 4" 480x864/480x854 AMOLED panel | |
| 8 | + | |
| 9 | +description: The Sony ACX424AKP and ACX424AKM are panels built around | |
| 10 | + the Novatek NT35560 display controller. The only difference is that | |
| 11 | + the AKM is configured to use 10 pixels less in the Y axis than the | |
| 12 | + AKP. | |
| 8 | 13 | |
| 9 | 14 | maintainers: |
| 10 | 15 | - Linus Walleij <linus.walleij@linaro.org> |
| @@ -14,7 +19,9 @@ allOf: · 3 unmodified lines | ||
| 14 | 19 | |
| 15 | 20 | properties: |
| 16 | 21 | compatible: |
| 17 | − const: sony,acx424akp | |
| 22 | + enum: | |
| 23 | + - sony,acx424akp | |
| 24 | + - sony,acx424akm | |
| 18 | 25 | reg: true |
| 19 | 26 | reset-gpios: true |
| 20 | 27 | vddi-supply: |
| @@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the · 74 unmodified lines | ||
| 75 | 75 | kernel log at initialization time and passes it to userspace through the |
| 76 | 76 | DRM_IOCTL_VERSION ioctl. |
| 77 | 77 | |
| 78 | +Module Initialization | |
| 79 | +--------------------- | |
| 80 | + | |
| 81 | +.. kernel-doc:: include/drm/drm_module.h | |
| 82 | + :doc: overview | |
| 83 | + | |
| 78 | 84 | Managing Ownership of the Framebuffer Aperture |
| 79 | 85 | ---------------------------------------------- |
| 80 | 86 | |
| @@ -232,34 +232,34 @@ HDCP Helper Functions Reference · 231 unmodified lines | ||
| 232 | 232 | Display Port Helper Functions Reference |
| 233 | 233 | ======================================= |
| 234 | 234 | |
| 235 | −.. kernel-doc:: drivers/gpu/drm/drm_dp_helper.c | |
| 235 | +.. kernel-doc:: drivers/gpu/drm/dp/drm_dp.c | |
| 236 | 236 | :doc: dp helpers |
| 237 | 237 | |
| 238 | −.. kernel-doc:: include/drm/drm_dp_helper.h | |
| 238 | +.. kernel-doc:: include/drm/dp/drm_dp_helper.h | |
| 239 | 239 | :internal: |
| 240 | 240 | |
| 241 | −.. kernel-doc:: drivers/gpu/drm/drm_dp_helper.c | |
| 241 | +.. kernel-doc:: drivers/gpu/drm/dp/drm_dp.c | |
| 242 | 242 | :export: |
| 243 | 243 | |
| 244 | 244 | Display Port CEC Helper Functions Reference |
| 245 | 245 | =========================================== |
| 246 | 246 | |
| 247 | −.. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c | |
| 247 | +.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_cec.c | |
| 248 | 248 | :doc: dp cec helpers |
| 249 | 249 | |
| 250 | −.. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c | |
| 250 | +.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_cec.c | |
| 251 | 251 | :export: |
| 252 | 252 | |
| 253 | 253 | Display Port Dual Mode Adaptor Helper Functions Reference |
| 254 | 254 | ========================================================= |
| 255 | 255 | |
| 256 | −.. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c | |
| 256 | +.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_dual_mode_helper.c | |
| 257 | 257 | :doc: dp dual mode helpers |
| 258 | 258 | |
| 259 | −.. kernel-doc:: include/drm/drm_dp_dual_mode_helper.h | |
| 259 | +.. kernel-doc:: include/drm/dp/drm_dp_dual_mode_helper.h | |
| 260 | 260 | :internal: |
| 261 | 261 | |
| 262 | −.. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c | |
| 262 | +.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_dual_mode_helper.c | |
| 263 | 263 | :export: |
| 264 | 264 | |
| 265 | 265 | Display Port MST Helpers |
| @@ -268,19 +268,19 @@ Display Port MST Helpers · 2 unmodified lines | ||
| 268 | 268 | Overview |
| 269 | 269 | -------- |
| 270 | 270 | |
| 271 | −.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | |
| 271 | +.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c | |
| 272 | 272 | :doc: dp mst helper |
| 273 | 273 | |
| 274 | −.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | |
| 274 | +.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c | |
| 275 | 275 | :doc: Branch device and port refcounting |
| 276 | 276 | |
| 277 | 277 | Functions Reference |
| 278 | 278 | ------------------- |
| 279 | 279 | |
| 280 | −.. kernel-doc:: include/drm/drm_dp_mst_helper.h | |
| 280 | +.. kernel-doc:: include/drm/dp/drm_dp_mst_helper.h | |
| 281 | 281 | :internal: |
| 282 | 282 | |
| 283 | −.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | |
| 283 | +.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c | |
| 284 | 284 | :export: |
| 285 | 285 | |
| 286 | 286 | Topology Lifetime Internals |
| @@ -289,7 +289,7 @@ Topology Lifetime Internals · 2 unmodified lines | ||
| 289 | 289 | These functions aren't exported to drivers, but are documented here to help make |
| 290 | 290 | the MST topology helpers easier to understand |
| 291 | 291 | |
| 292 | −.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | |
| 292 | +.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c | |
| 293 | 293 | :functions: drm_dp_mst_topology_try_get_mstb drm_dp_mst_topology_get_mstb |
| 294 | 294 | drm_dp_mst_topology_put_mstb |
| 295 | 295 | drm_dp_mst_topology_try_get_port drm_dp_mst_topology_get_port |
| @@ -423,12 +423,12 @@ Connector Functions Reference · 422 unmodified lines | ||
| 423 | 423 | Writeback Connectors |
| 424 | 424 | -------------------- |
| 425 | 425 | |
| 426 | −.. kernel-doc:: include/drm/drm_writeback.h | |
| 427 | − :internal: | |
| 428 | − | |
| 429 | 426 | .. kernel-doc:: drivers/gpu/drm/drm_writeback.c |
| 430 | 427 | :doc: overview |
| 431 | 428 | |
| 429 | +.. kernel-doc:: include/drm/drm_writeback.h | |
| 430 | + :internal: | |
| 431 | + | |
| 432 | 432 | .. kernel-doc:: drivers/gpu/drm/drm_writeback.c |
| 433 | 433 | :export: |
| 434 | 434 | |
| @@ -8,7 +8,7 @@ the very dynamic nature of many of that data, managing graphics memory · 7 unmodified lines | ||
| 8 | 8 | efficiently is thus crucial for the graphics stack and plays a central |
| 9 | 9 | role in the DRM infrastructure. |
| 10 | 10 | |
| 11 | −The DRM core includes two memory managers, namely Translation Table Maps | |
| 11 | +The DRM core includes two memory managers, namely Translation Table Manager | |
| 12 | 12 | (TTM) and Graphics Execution Manager (GEM). TTM was the first DRM memory |
| 13 | 13 | manager to be developed and tried to be a one-size-fits-them all |
| 14 | 14 | solution. It provides a single userspace API to accommodate the need of |
| @@ -467,6 +467,21 @@ Contact: Thomas Zimmermann <tzimmermann@suse.de> · 466 unmodified lines | ||
| 467 | 467 | |
| 468 | 468 | Level: Intermediate |
| 469 | 469 | |
| 470 | +Request memory regions in all drivers | |
| 471 | +------------------------------------- | |
| 472 | + | |
| 473 | +Go through all drivers and add code to request the memory regions that the | |
| 474 | +driver uses. This requires adding calls to request_mem_region(), | |
| 475 | +pci_request_region() or similar functions. Use helpers for managed cleanup | |
| 476 | +where possible. | |
| 477 | + | |
| 478 | +Drivers are pretty bad at doing this and there used to be conflicts among | |
| 479 | +DRM and fbdev drivers. Still, it's the correct thing to do. | |
| 480 | + | |
| 481 | +Contact: Thomas Zimmermann <tzimmermann@suse.de> | |
| 482 | + | |
| 483 | +Level: Starter | |
| 484 | + | |
| 470 | 485 | |
| 471 | 486 | Core refactorings |
| 472 | 487 | ================= |
| @@ -124,8 +124,6 @@ Add Plane Features · 123 unmodified lines | ||
| 124 | 124 | |
| 125 | 125 | There's lots of plane features we could add support for: |
| 126 | 126 | |
| 127 | −- Multiple overlay planes. [Good to get started] | |
| 128 | − | |
| 129 | 127 | - Clearing primary plane: clear primary plane before plane composition (at the |
| 130 | 128 | start) for correctness of pixel blend ops. It also guarantees alpha channel |
| 131 | 129 | is cleared in the target buffer for stable crc. [Good to get started] |
| @@ -55,7 +55,7 @@ static struct _ati_generic_private { · 54 unmodified lines | ||
| 55 | 55 | |
| 56 | 56 | static int ati_create_page_map(struct ati_page_map *page_map) |
| 57 | 57 | { |
| 58 | − int i, err = 0; | |
| 58 | + int i, err; | |
| 59 | 59 | |
| 60 | 60 | page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); |
| 61 | 61 | if (page_map->real == NULL) |
| @@ -63,6 +63,10 @@ static int ati_create_page_map(struct ati_page_map *page_map) · 1 unmodified line | ||
| 63 | 63 | |
| 64 | 64 | set_memory_uc((unsigned long)page_map->real, 1); |
| 65 | 65 | err = map_page_into_agp(virt_to_page(page_map->real)); |
| 66 | + if (err) { | |
| 67 | + free_page((unsigned long)page_map->real); | |
| 68 | + return err; | |
| 69 | + } | |
| 66 | 70 | page_map->remapped = page_map->real; |
| 67 | 71 | |
| 68 | 72 | for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { |
| @@ -303,7 +307,7 @@ static int ati_insert_memory(struct agp_memory * mem, · 234 unmodified lines | ||
| 303 | 307 | for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { |
| 304 | 308 | addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; |
| 305 | 309 | cur_gatt = GET_GATT(addr); |
| 306 | − writel(agp_bridge->driver->mask_memory(agp_bridge, | |
| 310 | + writel(agp_bridge->driver->mask_memory(agp_bridge, | |
| 307 | 311 | page_to_phys(mem->pages[i]), |
| 308 | 312 | mem->type), |
| 309 | 313 | cur_gatt+GET_GATT_OFF(addr)); |
| @@ -62,6 +62,7 @@ EXPORT_SYMBOL(agp_find_bridge); · 61 unmodified lines | ||
| 62 | 62 | |
| 63 | 63 | /** |
| 64 | 64 | * agp_backend_acquire - attempt to acquire an agp backend. |
| 65 | + * @pdev: the PCI device | |
| 65 | 66 | * |
| 66 | 67 | */ |
| 67 | 68 | struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev) |
| @@ -83,6 +84,7 @@ EXPORT_SYMBOL(agp_backend_acquire); · 15 unmodified lines | ||
| 83 | 84 | |
| 84 | 85 | /** |
| 85 | 86 | * agp_backend_release - release the lock on the agp backend. |
| 87 | + * @bridge: the AGP backend to release | |
| 86 | 88 | * |
| 87 | 89 | * The caller must insure that the graphics aperture translation table |
| 88 | 90 | * is read for use by another entity. |
| @@ -39,7 +39,9 @@ · 38 unmodified lines | ||
| 39 | 39 | #include <linux/fs.h> |
| 40 | 40 | #include <linux/sched.h> |
| 41 | 41 | #include <linux/uaccess.h> |
| 42 | + | |
| 42 | 43 | #include "agp.h" |
| 44 | +#include "compat_ioctl.h" | |
| 43 | 45 | |
| 44 | 46 | struct agp_front_data agp_fe; |
| 45 | 47 | |
| @@ -1017,7 +1019,7 @@ static long agp_ioctl(struct file *file, · 971 unmodified lines | ||
| 1017 | 1019 | case AGPIOC_UNBIND: |
| 1018 | 1020 | ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg); |
| 1019 | 1021 | break; |
| 1020 | − | |
| 1022 | + | |
| 1021 | 1023 | case AGPIOC_CHIPSET_FLUSH: |
| 1022 | 1024 | break; |
| 1023 | 1025 | } |
| @@ -261,7 +261,8 @@ static int nvidia_remove_memory(struct agp_memory *mem, off_t pg_start, int type · 260 unmodified lines | ||
| 261 | 261 | static void nvidia_tlbflush(struct agp_memory *mem) |
| 262 | 262 | { |
| 263 | 263 | unsigned long end; |
| 264 | − u32 wbc_reg, temp; | |
| 264 | + u32 wbc_reg; | |
| 265 | + u32 __maybe_unused temp; | |
| 265 | 266 | int i; |
| 266 | 267 | |
| 267 | 268 | /* flush chipset */ |
| @@ -262,13 +262,10 @@ static void serverworks_tlbflush(struct agp_memory *temp) · 261 unmodified lines | ||
| 262 | 262 | |
| 263 | 263 | static int serverworks_configure(void) |
| 264 | 264 | { |
| 265 | − struct aper_size_info_lvl2 *current_size; | |
| 266 | 265 | u32 temp; |
| 267 | 266 | u8 enable_reg; |
| 268 | 267 | u16 cap_reg; |
| 269 | 268 | |
| 270 | − current_size = A_SIZE_LVL2(agp_bridge->current_size); | |
| 271 | − | |
| 272 | 269 | /* Get the memory mapped registers */ |
| 273 | 270 | pci_read_config_dword(agp_bridge->dev, serverworks_private.mm_addr_ofs, &temp); |
| 274 | 271 | temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); |
| @@ -350,7 +347,7 @@ static int serverworks_insert_memory(struct agp_memory *mem, · 75 unmodified lines | ||
| 350 | 347 | for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { |
| 351 | 348 | addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; |
| 352 | 349 | cur_gatt = SVRWRKS_GET_GATT(addr); |
| 353 | − writel(agp_bridge->driver->mask_memory(agp_bridge, | |
| 350 | + writel(agp_bridge->driver->mask_memory(agp_bridge, | |
| 354 | 351 | page_to_phys(mem->pages[i]), mem->type), |
| 355 | 352 | cur_gatt+GET_GATT_OFF(addr)); |
| 356 | 353 | } |
| @@ -128,9 +128,6 @@ static int via_fetch_size_agp3(void) · 127 unmodified lines | ||
| 128 | 128 | static int via_configure_agp3(void) |
| 129 | 129 | { |
| 130 | 130 | u32 temp; |
| 131 | − struct aper_size_info_16 *current_size; | |
| 132 | − | |
| 133 | − current_size = A_SIZE_16(agp_bridge->current_size); | |
| 134 | 131 | |
| 135 | 132 | /* address to map to */ |
| 136 | 133 | agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, |
| @@ -542,57 +542,45 @@ EXPORT_SYMBOL(dma_resv_copy_fences); · 541 unmodified lines | ||
| 542 | 542 | * dma_resv_get_fences - Get an object's shared and exclusive |
| 543 | 543 | * fences without update side lock held |
| 544 | 544 | * @obj: the reservation object |
| 545 | − * @fence_excl: the returned exclusive fence (or NULL) | |
| 546 | − * @shared_count: the number of shared fences returned | |
| 547 | − * @shared: the array of shared fence ptrs returned (array is krealloc'd to | |
| 548 | − * the required size, and must be freed by caller) | |
| 545 | + * @write: true if we should return all fences | |
| 546 | + * @num_fences: the number of fences returned | |
| 547 | + * @fences: the array of fence ptrs returned (array is krealloc'd to the | |
| 548 | + * required size, and must be freed by caller) | |
| 549 | 549 | * |
| 550 | − * Retrieve all fences from the reservation object. If the pointer for the | |
| 551 | − * exclusive fence is not specified the fence is put into the array of the | |
| 552 | − * shared fences as well. Returns either zero or -ENOMEM. | |
| 550 | + * Retrieve all fences from the reservation object. | |
| 551 | + * Returns either zero or -ENOMEM. | |
| 553 | 552 | */ |
| 554 | −int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **fence_excl, | |
| 555 | − unsigned int *shared_count, struct dma_fence ***shared) | |
| 553 | +int dma_resv_get_fences(struct dma_resv *obj, bool write, | |
| 554 | + unsigned int *num_fences, struct dma_fence ***fences) | |
| 556 | 555 | { |
| 557 | 556 | struct dma_resv_iter cursor; |
| 558 | 557 | struct dma_fence *fence; |
| 559 | 558 | |
| 560 | − *shared_count = 0; | |
| 561 | − *shared = NULL; | |
| 559 | + *num_fences = 0; | |
| 560 | + *fences = NULL; | |
| 562 | 561 | |
| 563 | − if (fence_excl) | |
| 564 | − *fence_excl = NULL; | |
| 565 | − | |
| 566 | − dma_resv_iter_begin(&cursor, obj, true); | |
| 562 | + dma_resv_iter_begin(&cursor, obj, write); | |
| 567 | 563 | dma_resv_for_each_fence_unlocked(&cursor, fence) { |
| 568 | 564 | |
| 569 | 565 | if (dma_resv_iter_is_restarted(&cursor)) { |
| 570 | 566 | unsigned int count; |
| 571 | 567 | |
| 572 | − while (*shared_count) | |
| 573 | − dma_fence_put((*shared)[--(*shared_count)]); | |
| 574 | − | |
| 575 | − if (fence_excl) | |
| 576 | − dma_fence_put(*fence_excl); | |
| 568 | + while (*num_fences) | |
| 569 | + dma_fence_put((*fences)[--(*num_fences)]); | |
| 577 | 570 | |
| 578 | − count = cursor.shared_count; | |
| 579 | − count += fence_excl ? 0 : 1; | |
| 571 | + count = cursor.shared_count + 1; | |
| 580 | 572 | |
| 581 | 573 | /* Eventually re-allocate the array */ |
| 582 | − *shared = krealloc_array(*shared, count, | |
| 574 | + *fences = krealloc_array(*fences, count, | |
| 583 | 575 | sizeof(void *), |
| 584 | 576 | GFP_KERNEL); |
| 585 | − if (count && !*shared) { | |
| 577 | + if (count && !*fences) { | |
| 586 | 578 | dma_resv_iter_end(&cursor); |
| 587 | 579 | return -ENOMEM; |
| 588 | 580 | } |
| 589 | 581 | } |
| 590 | 582 | |
| 591 | − dma_fence_get(fence); | |
| 592 | − if (dma_resv_iter_is_exclusive(&cursor) && fence_excl) | |
| 593 | − *fence_excl = fence; | |
| 594 | − else | |
| 595 | − (*shared)[(*shared_count)++] = fence; | |
| 583 | + (*fences)[(*num_fences)++] = dma_fence_get(fence); | |
| 596 | 584 | } |
| 597 | 585 | dma_resv_iter_end(&cursor); |
| 598 | 586 | |
| @@ -275,7 +275,7 @@ static int test_shared_for_each_unlocked(void *arg) · 274 unmodified lines | ||
| 275 | 275 | |
| 276 | 276 | static int test_get_fences(void *arg, bool shared) |
| 277 | 277 | { |
| 278 | − struct dma_fence *f, *excl = NULL, **fences = NULL; | |
| 278 | + struct dma_fence *f, **fences = NULL; | |
| 279 | 279 | struct dma_resv resv; |
| 280 | 280 | int r, i; |
| 281 | 281 | |
| @@ -304,35 +304,19 @@ static int test_get_fences(void *arg, bool shared) · 22 unmodified lines | ||
| 304 | 304 | } |
| 305 | 305 | dma_resv_unlock(&resv); |
| 306 | 306 | |
| 307 | − r = dma_resv_get_fences(&resv, &excl, &i, &fences); | |
| 307 | + r = dma_resv_get_fences(&resv, shared, &i, &fences); | |
| 308 | 308 | if (r) { |
| 309 | 309 | pr_err("get_fences failed\n"); |
| 310 | 310 | goto err_free; |
| 311 | 311 | } |
| 312 | 312 | |
| 313 | − if (shared) { | |
| 314 | − if (excl != NULL) { | |
| 315 | − pr_err("get_fences returned unexpected excl fence\n"); | |
| 316 | − goto err_free; | |
| 317 | − } | |
| 318 | − if (i != 1 || fences[0] != f) { | |
| 319 | − pr_err("get_fences returned unexpected shared fence\n"); | |
| 320 | − goto err_free; | |
| 321 | − } | |
| 322 | − } else { | |
| 323 | − if (excl != f) { | |
| 324 | − pr_err("get_fences returned unexpected excl fence\n"); | |
| 325 | − goto err_free; | |
| 326 | − } | |
| 327 | − if (i != 0) { | |
| 328 | − pr_err("get_fences returned unexpected shared fence\n"); | |
| 329 | − goto err_free; | |
| 330 | − } | |
| 313 | + if (i != 1 || fences[0] != f) { | |
| 314 | + pr_err("get_fences returned unexpected fence\n"); | |
| 315 | + goto err_free; | |
| 331 | 316 | } |
| 332 | 317 | |
| 333 | 318 | dma_fence_signal(f); |
| 334 | 319 | err_free: |
| 335 | − dma_fence_put(excl); | |
| 336 | 320 | while (i--) |
| 337 | 321 | dma_fence_put(fences[i]); |
| 338 | 322 | kfree(fences); |
| @@ -190,6 +190,10 @@ static long udmabuf_create(struct miscdevice *device, · 189 unmodified lines | ||
| 190 | 190 | if (ubuf->pagecount > pglimit) |
| 191 | 191 | goto err; |
| 192 | 192 | } |
| 193 | + | |
| 194 | + if (!ubuf->pagecount) | |
| 195 | + goto err; | |
| 196 | + | |
| 193 | 197 | ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages), |
| 194 | 198 | GFP_KERNEL); |
| 195 | 199 | if (!ubuf->pages) { |
| @@ -99,7 +99,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si, · 98 unmodified lines | ||
| 99 | 99 | |
| 100 | 100 | /* setup IORESOURCE_MEM as framebuffer memory */ |
| 101 | 101 | memset(&res, 0, sizeof(res)); |
| 102 | − res.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | |
| 102 | + res.flags = IORESOURCE_MEM; | |
| 103 | 103 | res.name = simplefb_resname; |
| 104 | 104 | res.start = base; |
| 105 | 105 | res.end = res.start + length - 1; |
| @@ -68,6 +68,7 @@ config DRM_DEBUG_SELFTEST · 67 unmodified lines | ||
| 68 | 68 | depends on DRM |
| 69 | 69 | depends on DEBUG_KERNEL |
| 70 | 70 | select PRIME_NUMBERS |
| 71 | + select DRM_DP_HELPER | |
| 71 | 72 | select DRM_LIB_RANDOM |
| 72 | 73 | select DRM_KMS_HELPER |
| 73 | 74 | select DRM_EXPORT_FOR_TESTS if m |
| @@ -80,6 +81,12 @@ config DRM_DEBUG_SELFTEST · 6 unmodified lines | ||
| 80 | 81 | |
| 81 | 82 | If in doubt, say "N". |
| 82 | 83 | |
| 84 | +config DRM_DP_HELPER | |
| 85 | + tristate | |
| 86 | + depends on DRM | |
| 87 | + help | |
| 88 | + DRM helpers for DisplayPort. | |
| 89 | + | |
| 83 | 90 | config DRM_KMS_HELPER |
| 84 | 91 | tristate |
| 85 | 92 | depends on DRM |
| @@ -198,6 +205,12 @@ config DRM_TTM · 112 unmodified lines | ||
| 198 | 205 | GPU memory types. Will be enabled automatically if a device driver |
| 199 | 206 | uses it. |
| 200 | 207 | |
| 208 | +config DRM_BUDDY | |
| 209 | + tristate | |
| 210 | + depends on DRM | |
| 211 | + help | |
| 212 | + A page based buddy allocator | |
| 213 | + | |
| 201 | 214 | config DRM_VRAM_HELPER |
| 202 | 215 | tristate |
| 203 | 216 | depends on DRM |
| @@ -236,6 +249,7 @@ config DRM_RADEON · 32 unmodified lines | ||
| 236 | 249 | depends on DRM && PCI && MMU |
| 237 | 250 | depends on AGP || !AGP |
| 238 | 251 | select FW_LOADER |
| 252 | + select DRM_DP_HELPER | |
| 239 | 253 | select DRM_KMS_HELPER |
| 240 | 254 | select DRM_TTM |
| 241 | 255 | select DRM_TTM_HELPER |
| @@ -256,6 +270,7 @@ config DRM_AMDGPU · 14 unmodified lines | ||
| 256 | 270 | tristate "AMD GPU" |
| 257 | 271 | depends on DRM && PCI && MMU |
| 258 | 272 | select FW_LOADER |
| 273 | + select DRM_DP_HELPER | |
| 259 | 274 | select DRM_KMS_HELPER |
| 260 | 275 | select DRM_SCHED |
| 261 | 276 | select DRM_TTM |
| @@ -31,8 +31,6 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o · 30 unmodified lines | ||
| 31 | 31 | drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o |
| 32 | 32 | drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o drm_privacy_screen_x86.o |
| 33 | 33 | |
| 34 | −obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o | |
| 35 | − | |
| 36 | 34 | obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o |
| 37 | 35 | |
| 38 | 36 | drm_cma_helper-y := drm_gem_cma_helper.o |
| @@ -42,27 +40,26 @@ obj-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_cma_helper.o · 3 unmodified lines | ||
| 42 | 40 | drm_shmem_helper-y := drm_gem_shmem_helper.o |
| 43 | 41 | obj-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_shmem_helper.o |
| 44 | 42 | |
| 43 | +obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o | |
| 44 | + | |
| 45 | 45 | drm_vram_helper-y := drm_gem_vram_helper.o |
| 46 | 46 | obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o |
| 47 | 47 | |
| 48 | 48 | drm_ttm_helper-y := drm_gem_ttm_helper.o |
| 49 | 49 | obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o |
| 50 | 50 | |
| 51 | −drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o drm_dp_helper.o \ | |
| 51 | +drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \ | |
| 52 | 52 | drm_dsc.o drm_encoder_slave.o drm_flip_work.o drm_hdcp.o \ |
| 53 | 53 | drm_probe_helper.o \ |
| 54 | − drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ | |
| 55 | − drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ | |
| 54 | + drm_plane_helper.o drm_atomic_helper.o \ | |
| 55 | + drm_kms_helper_common.o \ | |
| 56 | 56 | drm_simple_kms_helper.o drm_modeset_helper.o \ |
| 57 | 57 | drm_scdc_helper.o drm_gem_atomic_helper.o \ |
| 58 | 58 | drm_gem_framebuffer_helper.o \ |
| 59 | 59 | drm_atomic_state_helper.o drm_damage_helper.o \ |
| 60 | 60 | drm_format_helper.o drm_self_refresh_helper.o drm_rect.o |
| 61 | − | |
| 62 | 61 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o |
| 63 | 62 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o |
| 64 | −drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o | |
| 65 | −drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o | |
| 66 | 63 | |
| 67 | 64 | obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o |
| 68 | 65 | obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/ |
| @@ -72,6 +69,7 @@ obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o · 3 unmodified lines | ||
| 72 | 69 | obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o |
| 73 | 70 | obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o |
| 74 | 71 | obj-y += arm/ |
| 72 | +obj-y += dp/ | |
| 75 | 73 | obj-$(CONFIG_DRM_TTM) += ttm/ |
| 76 | 74 | obj-$(CONFIG_DRM_SCHED) += scheduler/ |
| 77 | 75 | obj-$(CONFIG_DRM_TDFX) += tdfx/ |
| @@ -26,7 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | |
| 27 | 27 | #include <drm/drm_edid.h> |
| 28 | 28 | #include <drm/drm_fb_helper.h> |
| 29 | −#include <drm/drm_dp_helper.h> | |
| 29 | +#include <drm/dp/drm_dp_helper.h> | |
| 30 | 30 | #include <drm/drm_probe_helper.h> |
| 31 | 31 | #include <drm/amdgpu_drm.h> |
| 32 | 32 | #include "amdgpu.h" |
| @@ -175,7 +175,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector) · 142 unmodified lines | ||
| 175 | 175 | |
| 176 | 176 | /* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ |
| 177 | 177 | if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { |
| 178 | − if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) && | |
| 178 | + if ((connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) && | |
| 179 | 179 | (mode_clock * 5/4 <= max_tmds_clock)) |
| 180 | 180 | bpc = 10; |
| 181 | 181 | else |
| @@ -1274,14 +1274,11 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, · 1273 unmodified lines | ||
| 1274 | 1274 | /* |
| 1275 | 1275 | * Work around dma_resv shortcommings by wrapping up the |
| 1276 | 1276 | * submission in a dma_fence_chain and add it as exclusive |
| 1277 | − * fence, but first add the submission as shared fence to make | |
| 1278 | − * sure that shared fences never signal before the exclusive | |
| 1279 | − * one. | |
| 1277 | + * fence. | |
| 1280 | 1278 | */ |
| 1281 | 1279 | dma_fence_chain_init(chain, dma_resv_excl_fence(resv), |
| 1282 | 1280 | dma_fence_get(p->fence), 1); |
| 1283 | 1281 | |
| 1284 | − dma_resv_add_shared_fence(resv, p->fence); | |
| 1285 | 1282 | rcu_assign_pointer(resv->fence_excl, &chain->base); |
| 1286 | 1283 | e->chain = NULL; |
| 1287 | 1284 | } |
| @@ -200,8 +200,10 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, · 199 unmodified lines | ||
| 200 | 200 | goto unpin; |
| 201 | 201 | } |
| 202 | 202 | |
| 203 | − r = dma_resv_get_fences(new_abo->tbo.base.resv, NULL, | |
| 204 | − &work->shared_count, &work->shared); | |
| 203 | + /* TODO: Unify this with other drivers */ | |
| 204 | + r = dma_resv_get_fences(new_abo->tbo.base.resv, true, | |
| 205 | + &work->shared_count, | |
| 206 | + &work->shared); | |
| 205 | 207 | if (unlikely(r != 0)) { |
| 206 | 208 | DRM_ERROR("failed to get fences for buffer\n"); |
| 207 | 209 | goto unpin; |
| @@ -226,12 +226,6 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj, · 225 unmodified lines | ||
| 226 | 226 | if (!amdgpu_vm_ready(vm)) |
| 227 | 227 | goto out_unlock; |
| 228 | 228 | |
| 229 | − fence = dma_resv_excl_fence(bo->tbo.base.resv); | |
| 230 | − if (fence) { | |
| 231 | − amdgpu_bo_fence(bo, fence, true); | |
| 232 | − fence = NULL; | |
| 233 | − } | |
| 234 | − | |
| 235 | 229 | r = amdgpu_vm_clear_freed(adev, vm, &fence); |
| 236 | 230 | if (r || !fence) |
| 237 | 231 | goto out_unlock; |
| @@ -167,6 +167,7 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, · 166 unmodified lines | ||
| 167 | 167 | return 0; |
| 168 | 168 | |
| 169 | 169 | err_free: |
| 170 | + ttm_resource_fini(man, &node->base.base); | |
| 170 | 171 | kfree(node); |
| 171 | 172 | |
| 172 | 173 | err_out: |
| @@ -198,6 +199,7 @@ static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, · 25 unmodified lines | ||
| 198 | 199 | if (!(res->placement & TTM_PL_FLAG_TEMPORARY)) |
| 199 | 200 | atomic64_sub(res->num_pages, &mgr->used); |
| 200 | 201 | |
| 202 | + ttm_resource_fini(man, res); | |
| 201 | 203 | kfree(node); |
| 202 | 204 | } |
| 203 | 205 | |
| @@ -286,7 +288,8 @@ int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size) · 82 unmodified lines | ||
| 286 | 288 | man->use_tt = true; |
| 287 | 289 | man->func = &amdgpu_gtt_mgr_func; |
| 288 | 290 | |
| 289 | − ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT); | |
| 291 | + ttm_resource_manager_init(man, &adev->mman.bdev, | |
| 292 | + gtt_size >> PAGE_SHIFT); | |
| 290 | 293 | |
| 291 | 294 | start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; |
| 292 | 295 | size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; |
| @@ -112,7 +112,7 @@ void amdgpu_pasid_free_delayed(struct dma_resv *resv, · 111 unmodified lines | ||
| 112 | 112 | unsigned count; |
| 113 | 113 | int r; |
| 114 | 114 | |
| 115 | − r = dma_resv_get_fences(resv, NULL, &count, &fences); | |
| 115 | + r = dma_resv_get_fences(resv, true, &count, &fences); | |
| 116 | 116 | if (r) |
| 117 | 117 | goto fallback; |
| 118 | 118 | |
| @@ -33,7 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | #include <drm/drm_crtc.h> |
| 34 | 34 | #include <drm/drm_edid.h> |
| 35 | 35 | #include <drm/drm_encoder.h> |
| 36 | −#include <drm/drm_dp_helper.h> | |
| 36 | +#include <drm/dp/drm_dp_helper.h> | |
| 37 | 37 | #include <drm/drm_fixed.h> |
| 38 | 38 | #include <drm/drm_crtc_helper.h> |
| 39 | 39 | #include <drm/drm_fb_helper.h> |
| @@ -44,7 +44,7 @@ · 4 unmodified lines | ||
| 44 | 44 | #include <linux/hrtimer.h> |
| 45 | 45 | #include "amdgpu_irq.h" |
| 46 | 46 | |
| 47 | −#include <drm/drm_dp_mst_helper.h> | |
| 47 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 48 | 48 | #include "modules/inc/mod_freesync.h" |
| 49 | 49 | #include "amdgpu_dm_irq_params.h" |
| 50 | 50 | |
| @@ -95,6 +95,7 @@ static void amdgpu_preempt_mgr_del(struct ttm_resource_manager *man, · 94 unmodified lines | ||
| 95 | 95 | struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man); |
| 96 | 96 | |
| 97 | 97 | atomic64_sub(res->num_pages, &mgr->used); |
| 98 | + ttm_resource_fini(man, res); | |
| 98 | 99 | kfree(res); |
| 99 | 100 | } |
| 100 | 101 | |
| @@ -152,7 +153,7 @@ int amdgpu_preempt_mgr_init(struct amdgpu_device *adev) · 51 unmodified lines | ||
| 152 | 153 | man->use_tt = true; |
| 153 | 154 | man->func = &amdgpu_preempt_mgr_func; |
| 154 | 155 | |
| 155 | − ttm_resource_manager_init(man, (1 << 30)); | |
| 156 | + ttm_resource_manager_init(man, &adev->mman.bdev, (1 << 30)); | |
| 156 | 157 | |
| 157 | 158 | atomic64_set(&mgr->used, 0); |
| 158 | 159 | |
| @@ -2087,7 +2087,7 @@ static int amdgpu_mm_vram_table_show(struct seq_file *m, void *unused) · 2086 unmodified lines | ||
| 2087 | 2087 | TTM_PL_VRAM); |
| 2088 | 2088 | struct drm_printer p = drm_seq_file_printer(m); |
| 2089 | 2089 | |
| 2090 | − man->func->debug(man, &p); | |
| 2090 | + ttm_resource_manager_debug(man, &p); | |
| 2091 | 2091 | return 0; |
| 2092 | 2092 | } |
| 2093 | 2093 | |
| @@ -2105,7 +2105,7 @@ static int amdgpu_mm_tt_table_show(struct seq_file *m, void *unused) · 11 unmodified lines | ||
| 2105 | 2105 | TTM_PL_TT); |
| 2106 | 2106 | struct drm_printer p = drm_seq_file_printer(m); |
| 2107 | 2107 | |
| 2108 | − man->func->debug(man, &p); | |
| 2108 | + ttm_resource_manager_debug(man, &p); | |
| 2109 | 2109 | return 0; |
| 2110 | 2110 | } |
| 2111 | 2111 | |
| @@ -2116,7 +2116,7 @@ static int amdgpu_mm_gds_table_show(struct seq_file *m, void *unused) · 4 unmodified lines | ||
| 2116 | 2116 | AMDGPU_PL_GDS); |
| 2117 | 2117 | struct drm_printer p = drm_seq_file_printer(m); |
| 2118 | 2118 | |
| 2119 | − man->func->debug(man, &p); | |
| 2119 | + ttm_resource_manager_debug(man, &p); | |
| 2120 | 2120 | return 0; |
| 2121 | 2121 | } |
| 2122 | 2122 | |
| @@ -2127,7 +2127,7 @@ static int amdgpu_mm_gws_table_show(struct seq_file *m, void *unused) · 4 unmodified lines | ||
| 2127 | 2127 | AMDGPU_PL_GWS); |
| 2128 | 2128 | struct drm_printer p = drm_seq_file_printer(m); |
| 2129 | 2129 | |
| 2130 | − man->func->debug(man, &p); | |
| 2130 | + ttm_resource_manager_debug(man, &p); | |
| 2131 | 2131 | return 0; |
| 2132 | 2132 | } |
| 2133 | 2133 | |
| @@ -2138,7 +2138,7 @@ static int amdgpu_mm_oa_table_show(struct seq_file *m, void *unused) · 4 unmodified lines | ||
| 2138 | 2138 | AMDGPU_PL_OA); |
| 2139 | 2139 | struct drm_printer p = drm_seq_file_printer(m); |
| 2140 | 2140 | |
| 2141 | − man->func->debug(man, &p); | |
| 2141 | + ttm_resource_manager_debug(man, &p); | |
| 2142 | 2142 | return 0; |
| 2143 | 2143 | } |
| 2144 | 2144 | |
| @@ -472,6 +472,7 @@ error_free: · 471 unmodified lines | ||
| 472 | 472 | while (i--) |
| 473 | 473 | drm_mm_remove_node(&node->mm_nodes[i]); |
| 474 | 474 | spin_unlock(&mgr->lock); |
| 475 | + ttm_resource_fini(man, &node->base); | |
| 475 | 476 | kvfree(node); |
| 476 | 477 | |
| 477 | 478 | error_sub: |
| @@ -511,6 +512,7 @@ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, · 33 unmodified lines | ||
| 511 | 512 | atomic64_sub(usage, &mgr->usage); |
| 512 | 513 | atomic64_sub(vis_usage, &mgr->vis_usage); |
| 513 | 514 | |
| 515 | + ttm_resource_fini(man, res); | |
| 514 | 516 | kvfree(node); |
| 515 | 517 | } |
| 516 | 518 | |
| @@ -689,7 +691,8 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev) · 172 unmodified lines | ||
| 689 | 691 | struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; |
| 690 | 692 | struct ttm_resource_manager *man = &mgr->manager; |
| 691 | 693 | |
| 692 | − ttm_resource_manager_init(man, adev->gmc.real_vram_size >> PAGE_SHIFT); | |
| 694 | + ttm_resource_manager_init(man, &adev->mman.bdev, | |
| 695 | + adev->gmc.real_vram_size >> PAGE_SHIFT); | |
| 693 | 696 | |
| 694 | 697 | man->func = &amdgpu_vram_mgr_func; |
| 695 | 698 | |
| @@ -34,7 +34,7 @@ · 33 unmodified lines | ||
| 34 | 34 | #include "atombios_dp.h" |
| 35 | 35 | #include "amdgpu_connectors.h" |
| 36 | 36 | #include "amdgpu_atombios.h" |
| 37 | −#include <drm/drm_dp_helper.h> | |
| 37 | +#include <drm/dp/drm_dp_helper.h> | |
| 38 | 38 | |
| 39 | 39 | /* move these to drm_dp_helper.c/h */ |
| 40 | 40 | #define DP_LINK_CONFIGURATION_SIZE 9 |
| @@ -76,7 +76,7 @@ · 75 unmodified lines | ||
| 76 | 76 | #include <drm/drm_atomic.h> |
| 77 | 77 | #include <drm/drm_atomic_uapi.h> |
| 78 | 78 | #include <drm/drm_atomic_helper.h> |
| 79 | −#include <drm/drm_dp_mst_helper.h> | |
| 79 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 80 | 80 | #include <drm/drm_fb_helper.h> |
| 81 | 81 | #include <drm/drm_fourcc.h> |
| 82 | 82 | #include <drm/drm_edid.h> |
| @@ -5856,7 +5856,7 @@ static void fill_stream_properties_from_drm_display_mode( · 5773 unmodified lines | ||
| 5856 | 5856 | else if (drm_mode_is_420_also(info, mode_in) |
| 5857 | 5857 | && aconnector->force_yuv420_output) |
| 5858 | 5858 | timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; |
| 5859 | − else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) | |
| 5859 | + else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444) | |
| 5860 | 5860 | && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) |
| 5861 | 5861 | timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; |
| 5862 | 5862 | else |
| @@ -29,7 +29,7 @@ · 28 unmodified lines | ||
| 29 | 29 | #include <drm/drm_atomic.h> |
| 30 | 30 | #include <drm/drm_connector.h> |
| 31 | 31 | #include <drm/drm_crtc.h> |
| 32 | −#include <drm/drm_dp_mst_helper.h> | |
| 32 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 33 | 33 | #include <drm/drm_plane.h> |
| 34 | 34 | |
| 35 | 35 | /* |
| @@ -25,8 +25,8 @@ · 24 unmodified lines | ||
| 25 | 25 | |
| 26 | 26 | #include <drm/drm_atomic.h> |
| 27 | 27 | #include <drm/drm_atomic_helper.h> |
| 28 | −#include <drm/drm_dp_mst_helper.h> | |
| 29 | −#include <drm/drm_dp_helper.h> | |
| 28 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 29 | +#include <drm/dp/drm_dp_helper.h> | |
| 30 | 30 | #include "dm_services.h" |
| 31 | 31 | #include "amdgpu.h" |
| 32 | 32 | #include "amdgpu_dm.h" |
| @@ -27,7 +27,7 @@ · 26 unmodified lines | ||
| 27 | 27 | #include <dc_link.h> |
| 28 | 28 | #include <inc/link_hwss.h> |
| 29 | 29 | #include <inc/link_dpcd.h> |
| 30 | −#include "drm/drm_dp_helper.h" | |
| 30 | +#include <drm/dp/drm_dp_helper.h> | |
| 31 | 31 | #include <dc_dp_types.h> |
| 32 | 32 | #include "dm_helpers.h" |
| 33 | 33 | |
| @@ -25,7 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <drm/drm_dsc.h> |
| 26 | 26 | #include "dc_hw_types.h" |
| 27 | 27 | #include "dsc.h" |
| 28 | −#include <drm/drm_dp_helper.h> | |
| 28 | +#include <drm/dp/drm_dp_helper.h> | |
| 29 | 29 | #include "dc.h" |
| 30 | 30 | #include "rc_calc.h" |
| 31 | 31 | #include "fixed31_32.h" |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | ||
| 36 | 36 | #include <asm/byteorder.h> |
| 37 | 37 | |
| 38 | 38 | #include <drm/drm_print.h> |
| 39 | −#include <drm/drm_dp_helper.h> | |
| 39 | +#include <drm/dp/drm_dp_helper.h> | |
| 40 | 40 | |
| 41 | 41 | #include "cgs_common.h" |
| 42 | 42 | |
| @@ -26,7 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | #ifndef __DAL_DPCD_DEFS_H__ |
| 27 | 27 | #define __DAL_DPCD_DEFS_H__ |
| 28 | 28 | |
| 29 | −#include <drm/drm_dp_helper.h> | |
| 29 | +#include <drm/dp/drm_dp_helper.h> | |
| 30 | 30 | #ifndef DP_SINK_HW_REVISION_START // can remove this once the define gets into linux drm_dp_helper.h |
| 31 | 31 | #define DP_SINK_HW_REVISION_START 0x409 |
| 32 | 32 | #endif |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | #include "hdcp_log.h" |
| 31 | 31 | |
| 32 | 32 | #include <drm/drm_hdcp.h> |
| 33 | −#include <drm/drm_dp_helper.h> | |
| 33 | +#include <drm/dp/drm_dp_helper.h> | |
| 34 | 34 | |
| 35 | 35 | enum mod_hdcp_trans_input_result { |
| 36 | 36 | UNKNOWN = 0, |
| @@ -1078,11 +1078,11 @@ static void d71_improc_update(struct komeda_component *c, · 1077 unmodified lines | ||
| 1078 | 1078 | mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; |
| 1079 | 1079 | |
| 1080 | 1080 | /* config color format */ |
| 1081 | − if (st->color_format == DRM_COLOR_FORMAT_YCRCB420) | |
| 1081 | + if (st->color_format == DRM_COLOR_FORMAT_YCBCR420) | |
| 1082 | 1082 | ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; |
| 1083 | − else if (st->color_format == DRM_COLOR_FORMAT_YCRCB422) | |
| 1083 | + else if (st->color_format == DRM_COLOR_FORMAT_YCBCR422) | |
| 1084 | 1084 | ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422; |
| 1085 | − else if (st->color_format == DRM_COLOR_FORMAT_YCRCB444) | |
| 1085 | + else if (st->color_format == DRM_COLOR_FORMAT_YCBCR444) | |
| 1086 | 1086 | ctrl |= IPS_CTRL_YUV; |
| 1087 | 1087 | |
| 1088 | 1088 | malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl); |
| @@ -1144,11 +1144,11 @@ static int d71_improc_init(struct d71_dev *d71, · 55 unmodified lines | ||
| 1144 | 1144 | improc = to_improc(c); |
| 1145 | 1145 | improc->supported_color_depths = BIT(8) | BIT(10); |
| 1146 | 1146 | improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 | |
| 1147 | − DRM_COLOR_FORMAT_YCRCB444 | | |
| 1148 | − DRM_COLOR_FORMAT_YCRCB422; | |
| 1147 | + DRM_COLOR_FORMAT_YCBCR444 | | |
| 1148 | + DRM_COLOR_FORMAT_YCBCR422; | |
| 1149 | 1149 | value = malidp_read32(reg, BLK_INFO); |
| 1150 | 1150 | if (value & IPS_INFO_CHD420) |
| 1151 | − improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420; | |
| 1151 | + improc->supported_color_formats |= DRM_COLOR_FORMAT_YCBCR420; | |
| 1152 | 1152 | |
| 1153 | 1153 | improc->supports_csc = true; |
| 1154 | 1154 | improc->supports_gamma = true; |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/platform_device.h> |
| 10 | 10 | #include <linux/component.h> |
| 11 | 11 | #include <linux/pm_runtime.h> |
| 12 | +#include <drm/drm_module.h> | |
| 12 | 13 | #include <drm/drm_of.h> |
| 13 | 14 | #include "komeda_dev.h" |
| 14 | 15 | #include "komeda_kms.h" |
| @@ -198,7 +199,7 @@ static struct platform_driver komeda_platform_driver = { · 183 unmodified lines | ||
| 198 | 199 | }, |
| 199 | 200 | }; |
| 200 | 201 | |
| 201 | −module_platform_driver(komeda_platform_driver); | |
| 202 | +drm_module_platform_driver(komeda_platform_driver); | |
| 202 | 203 | |
| 203 | 204 | MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>"); |
| 204 | 205 | MODULE_DESCRIPTION("Komeda KMS driver"); |
| @@ -30,6 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | #include <drm/drm_gem_cma_helper.h> |
| 31 | 31 | #include <drm/drm_gem_framebuffer_helper.h> |
| 32 | 32 | #include <drm/drm_modeset_helper.h> |
| 33 | +#include <drm/drm_module.h> | |
| 33 | 34 | #include <drm/drm_of.h> |
| 34 | 35 | #include <drm/drm_probe_helper.h> |
| 35 | 36 | #include <drm/drm_vblank.h> |
| @@ -434,7 +435,7 @@ static struct platform_driver hdlcd_platform_driver = { · 398 unmodified lines | ||
| 434 | 435 | }, |
| 435 | 436 | }; |
| 436 | 437 | |
| 437 | −module_platform_driver(hdlcd_platform_driver); | |
| 438 | +drm_module_platform_driver(hdlcd_platform_driver); | |
| 438 | 439 | |
| 439 | 440 | MODULE_AUTHOR("Liviu Dudau"); |
| 440 | 441 | MODULE_DESCRIPTION("ARM HDLCD DRM driver"); |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <drm/drm_gem_cma_helper.h> |
| 26 | 26 | #include <drm/drm_gem_framebuffer_helper.h> |
| 27 | 27 | #include <drm/drm_modeset_helper.h> |
| 28 | +#include <drm/drm_module.h> | |
| 28 | 29 | #include <drm/drm_of.h> |
| 29 | 30 | #include <drm/drm_probe_helper.h> |
| 30 | 31 | #include <drm/drm_vblank.h> |
| @@ -1008,7 +1009,7 @@ static struct platform_driver malidp_platform_driver = { · 977 unmodified lines | ||
| 1008 | 1009 | }, |
| 1009 | 1010 | }; |
| 1010 | 1011 | |
| 1011 | −module_platform_driver(malidp_platform_driver); | |
| 1012 | +drm_module_platform_driver(malidp_platform_driver); | |
| 1012 | 1013 | |
| 1013 | 1014 | MODULE_AUTHOR("Liviu Dudau <Liviu.Dudau@arm.com>"); |
| 1014 | 1015 | MODULE_DESCRIPTION("ARM Mali DP DRM driver"); |
| @@ -34,6 +34,7 @@ · 33 unmodified lines | ||
| 34 | 34 | #include <drm/drm_crtc_helper.h> |
| 35 | 35 | #include <drm/drm_drv.h> |
| 36 | 36 | #include <drm/drm_gem_vram_helper.h> |
| 37 | +#include <drm/drm_module.h> | |
| 37 | 38 | #include <drm/drm_probe_helper.h> |
| 38 | 39 | |
| 39 | 40 | #include "ast_drv.h" |
| @@ -230,22 +231,7 @@ static struct pci_driver ast_pci_driver = { · 190 unmodified lines | ||
| 230 | 231 | .driver.pm = &ast_pm_ops, |
| 231 | 232 | }; |
| 232 | 233 | |
| 233 | −static int __init ast_init(void) | |
| 234 | −{ | |
| 235 | − if (drm_firmware_drivers_only() && ast_modeset == -1) | |
| 236 | − return -EINVAL; | |
| 237 | − | |
| 238 | − if (ast_modeset == 0) | |
| 239 | − return -EINVAL; | |
| 240 | − return pci_register_driver(&ast_pci_driver); | |
| 241 | −} | |
| 242 | −static void __exit ast_exit(void) | |
| 243 | −{ | |
| 244 | − pci_unregister_driver(&ast_pci_driver); | |
| 245 | −} | |
| 246 | − | |
| 247 | −module_init(ast_init); | |
| 248 | −module_exit(ast_exit); | |
| 234 | +drm_module_pci_driver_if_modeset(ast_pci_driver, ast_modeset); | |
| 249 | 235 | |
| 250 | 236 | MODULE_AUTHOR(DRIVER_AUTHOR); |
| 251 | 237 | MODULE_DESCRIPTION(DRIVER_DESC); |
| @@ -209,6 +209,8 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) · 208 unmodified lines | ||
| 209 | 209 | if (ast->chip == AST2500 && |
| 210 | 210 | scu_rev == 0x100) /* ast2510 */ |
| 211 | 211 | ast->support_wide_screen = true; |
| 212 | + if (ast->chip == AST2600) /* ast2600 */ | |
| 213 | + ast->support_wide_screen = true; | |
| 212 | 214 | } |
| 213 | 215 | break; |
| 214 | 216 | } |
| @@ -471,7 +471,10 @@ static void ast_set_color_reg(struct ast_private *ast, · 470 unmodified lines | ||
| 471 | 471 | static void ast_set_crtthd_reg(struct ast_private *ast) |
| 472 | 472 | { |
| 473 | 473 | /* Set Threshold */ |
| 474 | − if (ast->chip == AST2300 || ast->chip == AST2400 || | |
| 474 | + if (ast->chip == AST2600) { | |
| 475 | + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0xe0); | |
| 476 | + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0xa0); | |
| 477 | + } else if (ast->chip == AST2300 || ast->chip == AST2400 || | |
| 475 | 478 | ast->chip == AST2500) { |
| 476 | 479 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78); |
| 477 | 480 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60); |
| @@ -30,6 +30,7 @@ config DRM_CDNS_DSI · 29 unmodified lines | ||
| 30 | 30 | config DRM_CHIPONE_ICN6211 |
| 31 | 31 | tristate "Chipone ICN6211 MIPI-DSI/RGB Converter bridge" |
| 32 | 32 | depends on OF |
| 33 | + depends on DRM_KMS_HELPER | |
| 33 | 34 | select DRM_MIPI_DSI |
| 34 | 35 | select DRM_PANEL_BRIDGE |
| 35 | 36 | help |
| @@ -183,6 +184,7 @@ config DRM_PARADE_PS8640 · 147 unmodified lines | ||
| 183 | 184 | tristate "Parade PS8640 MIPI DSI to eDP Converter" |
| 184 | 185 | depends on OF |
| 185 | 186 | select DRM_DP_AUX_BUS |
| 187 | + select DRM_DP_HELPER | |
| 186 | 188 | select DRM_KMS_HELPER |
| 187 | 189 | select DRM_MIPI_DSI |
| 188 | 190 | select DRM_PANEL |
| @@ -253,6 +255,7 @@ config DRM_TOSHIBA_TC358764 · 64 unmodified lines | ||
| 253 | 255 | config DRM_TOSHIBA_TC358767 |
| 254 | 256 | tristate "Toshiba TC358767 eDP bridge" |
| 255 | 257 | depends on OF |
| 258 | + select DRM_DP_HELPER | |
| 256 | 259 | select DRM_KMS_HELPER |
| 257 | 260 | select REGMAP_I2C |
| 258 | 261 | select DRM_PANEL |
| @@ -272,6 +275,7 @@ config DRM_TOSHIBA_TC358768 · 13 unmodified lines | ||
| 272 | 275 | config DRM_TOSHIBA_TC358775 |
| 273 | 276 | tristate "Toshiba TC358775 DSI/LVDS bridge" |
| 274 | 277 | depends on OF |
| 278 | + select DRM_DP_HELPER | |
| 275 | 279 | select DRM_KMS_HELPER |
| 276 | 280 | select REGMAP_I2C |
| 277 | 281 | select DRM_PANEL |
| @@ -299,6 +303,7 @@ config DRM_TI_SN65DSI83 · 21 unmodified lines | ||
| 299 | 303 | config DRM_TI_SN65DSI86 |
| 300 | 304 | tristate "TI SN65DSI86 DSI to eDP bridge" |
| 301 | 305 | depends on OF |
| 306 | + select DRM_DP_HELPER | |
| 302 | 307 | select DRM_KMS_HELPER |
| 303 | 308 | select REGMAP_I2C |
| 304 | 309 | select DRM_PANEL |
| @@ -169,6 +169,7 @@ · 168 unmodified lines | ||
| 169 | 169 | #define ADV7511_PACKET_ENABLE_SPARE2 BIT(1) |
| 170 | 170 | #define ADV7511_PACKET_ENABLE_SPARE1 BIT(0) |
| 171 | 171 | |
| 172 | +#define ADV7535_REG_POWER2_HPD_OVERRIDE BIT(6) | |
| 172 | 173 | #define ADV7511_REG_POWER2_HPD_SRC_MASK 0xc0 |
| 173 | 174 | #define ADV7511_REG_POWER2_HPD_SRC_BOTH 0x00 |
| 174 | 175 | #define ADV7511_REG_POWER2_HPD_SRC_HPD 0x40 |
| @@ -223,7 +223,7 @@ static void adv7511_set_config_csc(struct adv7511 *adv7511, · 222 unmodified lines | ||
| 223 | 223 | config.csc_coefficents = adv7511_csc_ycbcr_to_rgb; |
| 224 | 224 | |
| 225 | 225 | if ((connector->display_info.color_formats & |
| 226 | − DRM_COLOR_FORMAT_YCRCB422) && | |
| 226 | + DRM_COLOR_FORMAT_YCBCR422) && | |
| 227 | 227 | config.hdmi_mode) { |
| 228 | 228 | config.csc_enable = false; |
| 229 | 229 | config.avi_infoframe.colorspace = |
| @@ -351,11 +351,17 @@ static void __adv7511_power_on(struct adv7511 *adv7511) · 121 unmodified lines | ||
| 351 | 351 | * from standby or are enabled. When the HPD goes low the adv7511 is |
| 352 | 352 | * reset and the outputs are disabled which might cause the monitor to |
| 353 | 353 | * go to standby again. To avoid this we ignore the HPD pin for the |
| 354 | − * first few seconds after enabling the output. | |
| 354 | + * first few seconds after enabling the output. On the other hand | |
| 355 | + * adv7535 require to enable HPD Override bit for proper HPD. | |
| 355 | 356 | */ |
| 356 | − regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | |
| 357 | − ADV7511_REG_POWER2_HPD_SRC_MASK, | |
| 358 | − ADV7511_REG_POWER2_HPD_SRC_NONE); | |
| 357 | + if (adv7511->type == ADV7535) | |
| 358 | + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | |
| 359 | + ADV7535_REG_POWER2_HPD_OVERRIDE, | |
| 360 | + ADV7535_REG_POWER2_HPD_OVERRIDE); | |
| 361 | + else | |
| 362 | + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | |
| 363 | + ADV7511_REG_POWER2_HPD_SRC_MASK, | |
| 364 | + ADV7511_REG_POWER2_HPD_SRC_NONE); | |
| 359 | 365 | } |
| 360 | 366 | |
| 361 | 367 | static void adv7511_power_on(struct adv7511 *adv7511) |
| @@ -375,6 +381,10 @@ static void adv7511_power_on(struct adv7511 *adv7511) · 13 unmodified lines | ||
| 375 | 381 | static void __adv7511_power_off(struct adv7511 *adv7511) |
| 376 | 382 | { |
| 377 | 383 | /* TODO: setup additional power down modes */ |
| 384 | + if (adv7511->type == ADV7535) | |
| 385 | + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | |
| 386 | + ADV7535_REG_POWER2_HPD_OVERRIDE, 0); | |
| 387 | + | |
| 378 | 388 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, |
| 379 | 389 | ADV7511_POWER_POWER_DOWN, |
| 380 | 390 | ADV7511_POWER_POWER_DOWN); |
| @@ -672,9 +682,14 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) · 291 unmodified lines | ||
| 672 | 682 | status = connector_status_disconnected; |
| 673 | 683 | } else { |
| 674 | 684 | /* Renable HPD sensing */ |
| 675 | − regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | |
| 676 | − ADV7511_REG_POWER2_HPD_SRC_MASK, | |
| 677 | − ADV7511_REG_POWER2_HPD_SRC_BOTH); | |
| 685 | + if (adv7511->type == ADV7535) | |
| 686 | + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | |
| 687 | + ADV7535_REG_POWER2_HPD_OVERRIDE, | |
| 688 | + ADV7535_REG_POWER2_HPD_OVERRIDE); | |
| 689 | + else | |
| 690 | + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | |
| 691 | + ADV7511_REG_POWER2_HPD_SRC_MASK, | |
| 692 | + ADV7511_REG_POWER2_HPD_SRC_BOTH); | |
| 678 | 693 | } |
| 679 | 694 | |
| 680 | 695 | adv7511->status = status; |
| @@ -29,7 +29,7 @@ static void adv7511_dsi_config_timing_gen(struct adv7511 *adv) · 28 unmodified lines | ||
| 29 | 29 | struct mipi_dsi_device *dsi = adv->dsi; |
| 30 | 30 | struct drm_display_mode *mode = &adv->curr_mode; |
| 31 | 31 | unsigned int hsw, hfp, hbp, vsw, vfp, vbp; |
| 32 | − u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */ | |
| 32 | + static const u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */ | |
| 33 | 33 | |
| 34 | 34 | hsw = mode->hsync_end - mode->hsync_start; |
| 35 | 35 | hfp = mode->hsync_start - mode->hdisplay; |
| @@ -3,6 +3,7 @@ config DRM_ANALOGIX_ANX6345 · 2 unmodified lines | ||
| 3 | 3 | tristate "Analogix ANX6345 bridge" |
| 4 | 4 | depends on OF |
| 5 | 5 | select DRM_ANALOGIX_DP |
| 6 | + select DRM_DP_HELPER | |
| 6 | 7 | select DRM_KMS_HELPER |
| 7 | 8 | select REGMAP_I2C |
| 8 | 9 | help |
| @@ -14,6 +15,7 @@ config DRM_ANALOGIX_ANX6345 · 5 unmodified lines | ||
| 14 | 15 | config DRM_ANALOGIX_ANX78XX |
| 15 | 16 | tristate "Analogix ANX78XX bridge" |
| 16 | 17 | select DRM_ANALOGIX_DP |
| 18 | + select DRM_DP_HELPER | |
| 17 | 19 | select DRM_KMS_HELPER |
| 18 | 20 | select REGMAP_I2C |
| 19 | 21 | help |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <drm/drm_bridge.h> |
| 23 | 23 | #include <drm/drm_crtc.h> |
| 24 | 24 | #include <drm/drm_crtc_helper.h> |
| 25 | −#include <drm/drm_dp_helper.h> | |
| 25 | +#include <drm/dp/drm_dp_helper.h> | |
| 26 | 26 | #include <drm/drm_edid.h> |
| 27 | 27 | #include <drm/drm_of.h> |
| 28 | 28 | #include <drm/drm_panel.h> |
| @@ -21,7 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <drm/drm_atomic_helper.h> |
| 22 | 22 | #include <drm/drm_bridge.h> |
| 23 | 23 | #include <drm/drm_crtc.h> |
| 24 | −#include <drm/drm_dp_helper.h> | |
| 24 | +#include <drm/dp/drm_dp_helper.h> | |
| 25 | 25 | #include <drm/drm_edid.h> |
| 26 | 26 | #include <drm/drm_print.h> |
| 27 | 27 | #include <drm/drm_probe_helper.h> |
| @@ -8,7 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | #include <linux/regmap.h> |
| 9 | 9 | |
| 10 | 10 | #include <drm/drm.h> |
| 11 | −#include <drm/drm_dp_helper.h> | |
| 11 | +#include <drm/dp/drm_dp_helper.h> | |
| 12 | 12 | #include <drm/drm_print.h> |
| 13 | 13 | |
| 14 | 14 | #include "analogix-i2c-dptx.h" |
| @@ -1537,9 +1537,9 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, · 1536 unmodified lines | ||
| 1537 | 1537 | video->color_depth = COLOR_8; |
| 1538 | 1538 | break; |
| 1539 | 1539 | } |
| 1540 | − if (display_info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | |
| 1540 | + if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR444) | |
| 1541 | 1541 | video->color_space = COLOR_YCBCR444; |
| 1542 | − else if (display_info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | |
| 1542 | + else if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422) | |
| 1543 | 1543 | video->color_space = COLOR_YCBCR422; |
| 1544 | 1544 | else |
| 1545 | 1545 | video->color_space = COLOR_RGB; |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #define _ANALOGIX_DP_CORE_H |
| 11 | 11 | |
| 12 | 12 | #include <drm/drm_crtc.h> |
| 13 | −#include <drm/drm_dp_helper.h> | |
| 13 | +#include <drm/dp/drm_dp_helper.h> | |
| 14 | 14 | |
| 15 | 15 | #define DP_TIMEOUT_LOOP_COUNT 100 |
| 16 | 16 | #define MAX_CR_LOOP 5 |
| @@ -24,8 +24,9 @@ · 23 unmodified lines | ||
| 24 | 24 | #include <drm/drm_atomic_helper.h> |
| 25 | 25 | #include <drm/drm_bridge.h> |
| 26 | 26 | #include <drm/drm_crtc_helper.h> |
| 27 | −#include <drm/drm_dp_helper.h> | |
| 27 | +#include <drm/dp/drm_dp_helper.h> | |
| 28 | 28 | #include <drm/drm_edid.h> |
| 29 | +#include <drm/drm_hdcp.h> | |
| 29 | 30 | #include <drm/drm_mipi_dsi.h> |
| 30 | 31 | #include <drm/drm_of.h> |
| 31 | 32 | #include <drm/drm_panel.h> |
| @@ -213,6 +214,65 @@ static int wait_aux_op_finish(struct anx7625_data *ctx) · 181 unmodified lines | ||
| 213 | 214 | return 0; |
| 214 | 215 | } |
| 215 | 216 | |
| 217 | +static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, | |
| 218 | + u32 address, u8 len, u8 *buf) | |
| 219 | +{ | |
| 220 | + struct device *dev = &ctx->client->dev; | |
| 221 | + int ret; | |
| 222 | + u8 addrh, addrm, addrl; | |
| 223 | + u8 cmd; | |
| 224 | + | |
| 225 | + if (len > MAX_DPCD_BUFFER_SIZE) { | |
| 226 | + dev_err(dev, "exceed aux buffer len.\n"); | |
| 227 | + return -EINVAL; | |
| 228 | + } | |
| 229 | + | |
| 230 | + addrl = address & 0xFF; | |
| 231 | + addrm = (address >> 8) & 0xFF; | |
| 232 | + addrh = (address >> 16) & 0xFF; | |
| 233 | + | |
| 234 | + cmd = DPCD_CMD(len, DPCD_READ); | |
| 235 | + cmd = ((len - 1) << 4) | 0x09; | |
| 236 | + | |
| 237 | + /* Set command and length */ | |
| 238 | + ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 239 | + AP_AUX_COMMAND, cmd); | |
| 240 | + | |
| 241 | + /* Set aux access address */ | |
| 242 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 243 | + AP_AUX_ADDR_7_0, addrl); | |
| 244 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 245 | + AP_AUX_ADDR_15_8, addrm); | |
| 246 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 247 | + AP_AUX_ADDR_19_16, addrh); | |
| 248 | + | |
| 249 | + /* Enable aux access */ | |
| 250 | + ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client, | |
| 251 | + AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN); | |
| 252 | + | |
| 253 | + if (ret < 0) { | |
| 254 | + dev_err(dev, "cannot access aux related register.\n"); | |
| 255 | + return -EIO; | |
| 256 | + } | |
| 257 | + | |
| 258 | + usleep_range(2000, 2100); | |
| 259 | + | |
| 260 | + ret = wait_aux_op_finish(ctx); | |
| 261 | + if (ret) { | |
| 262 | + dev_err(dev, "aux IO error: wait aux op finish.\n"); | |
| 263 | + return ret; | |
| 264 | + } | |
| 265 | + | |
| 266 | + ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client, | |
| 267 | + AP_AUX_BUFF_START, len, buf); | |
| 268 | + if (ret < 0) { | |
| 269 | + dev_err(dev, "read dpcd register failed\n"); | |
| 270 | + return -EIO; | |
| 271 | + } | |
| 272 | + | |
| 273 | + return 0; | |
| 274 | +} | |
| 275 | + | |
| 216 | 276 | static int anx7625_video_mute_control(struct anx7625_data *ctx, |
| 217 | 277 | u8 status) |
| 218 | 278 | { |
| @@ -669,6 +729,165 @@ static int anx7625_dpi_config(struct anx7625_data *ctx) · 450 unmodified lines | ||
| 669 | 729 | return ret; |
| 670 | 730 | } |
| 671 | 731 | |
| 732 | +static int anx7625_read_flash_status(struct anx7625_data *ctx) | |
| 733 | +{ | |
| 734 | + return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, R_RAM_CTRL); | |
| 735 | +} | |
| 736 | + | |
| 737 | +static int anx7625_hdcp_key_probe(struct anx7625_data *ctx) | |
| 738 | +{ | |
| 739 | + int ret, val; | |
| 740 | + struct device *dev = &ctx->client->dev; | |
| 741 | + u8 ident[FLASH_BUF_LEN]; | |
| 742 | + | |
| 743 | + ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 744 | + FLASH_ADDR_HIGH, 0x91); | |
| 745 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 746 | + FLASH_ADDR_LOW, 0xA0); | |
| 747 | + if (ret < 0) { | |
| 748 | + dev_err(dev, "IO error : set key flash address.\n"); | |
| 749 | + return ret; | |
| 750 | + } | |
| 751 | + | |
| 752 | + ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 753 | + FLASH_LEN_HIGH, (FLASH_BUF_LEN - 1) >> 8); | |
| 754 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 755 | + FLASH_LEN_LOW, (FLASH_BUF_LEN - 1) & 0xFF); | |
| 756 | + if (ret < 0) { | |
| 757 | + dev_err(dev, "IO error : set key flash len.\n"); | |
| 758 | + return ret; | |
| 759 | + } | |
| 760 | + | |
| 761 | + ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 762 | + R_FLASH_RW_CTRL, FLASH_READ); | |
| 763 | + ret |= readx_poll_timeout(anx7625_read_flash_status, | |
| 764 | + ctx, val, | |
| 765 | + ((val & FLASH_DONE) || (val < 0)), | |
| 766 | + 2000, | |
| 767 | + 2000 * 150); | |
| 768 | + if (ret) { | |
| 769 | + dev_err(dev, "flash read access fail!\n"); | |
| 770 | + return -EIO; | |
| 771 | + } | |
| 772 | + | |
| 773 | + ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client, | |
| 774 | + FLASH_BUF_BASE_ADDR, | |
| 775 | + FLASH_BUF_LEN, ident); | |
| 776 | + if (ret < 0) { | |
| 777 | + dev_err(dev, "read flash data fail!\n"); | |
| 778 | + return -EIO; | |
| 779 | + } | |
| 780 | + | |
| 781 | + if (ident[29] == 0xFF && ident[30] == 0xFF && ident[31] == 0xFF) | |
| 782 | + return -EINVAL; | |
| 783 | + | |
| 784 | + return 0; | |
| 785 | +} | |
| 786 | + | |
| 787 | +static int anx7625_hdcp_key_load(struct anx7625_data *ctx) | |
| 788 | +{ | |
| 789 | + int ret; | |
| 790 | + struct device *dev = &ctx->client->dev; | |
| 791 | + | |
| 792 | + /* Select HDCP 1.4 KEY */ | |
| 793 | + ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 794 | + R_BOOT_RETRY, 0x12); | |
| 795 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 796 | + FLASH_ADDR_HIGH, HDCP14KEY_START_ADDR >> 8); | |
| 797 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 798 | + FLASH_ADDR_LOW, HDCP14KEY_START_ADDR & 0xFF); | |
| 799 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 800 | + R_RAM_LEN_H, HDCP14KEY_SIZE >> 12); | |
| 801 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 802 | + R_RAM_LEN_L, HDCP14KEY_SIZE >> 4); | |
| 803 | + | |
| 804 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 805 | + R_RAM_ADDR_H, 0); | |
| 806 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 807 | + R_RAM_ADDR_L, 0); | |
| 808 | + /* Enable HDCP 1.4 KEY load */ | |
| 809 | + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | |
| 810 | + R_RAM_CTRL, DECRYPT_EN | LOAD_START); | |
| 811 | + dev_dbg(dev, "load HDCP 1.4 key done\n"); | |
| 812 | + return ret; | |
| 813 | +} | |
| 814 | + | |
| 815 | +static int anx7625_hdcp_disable(struct anx7625_data *ctx) | |
| 816 | +{ | |
| 817 | + int ret; | |
| 818 | + struct device *dev = &ctx->client->dev; | |
| 819 | + | |
| 820 | + dev_dbg(dev, "disable HDCP 1.4\n"); | |
| 821 | + | |
| 822 | + /* Disable HDCP */ | |
| 823 | + ret = anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f); | |
| 824 | + /* Try auth flag */ | |
| 825 | + ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10); | |
| 826 | + /* Interrupt for DRM */ | |
| 827 | + ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01); | |
| 828 | + if (ret < 0) | |
| 829 | + dev_err(dev, "fail to disable HDCP\n"); | |
| 830 | + | |
| 831 | + return anx7625_write_and(ctx, ctx->i2c.tx_p0_client, | |
| 832 | + TX_HDCP_CTRL0, ~HARD_AUTH_EN & 0xFF); | |
| 833 | +} | |
| 834 | + | |
| 835 | +static int anx7625_hdcp_enable(struct anx7625_data *ctx) | |
| 836 | +{ | |
| 837 | + u8 bcap; | |
| 838 | + int ret; | |
| 839 | + struct device *dev = &ctx->client->dev; | |
| 840 | + | |
| 841 | + ret = anx7625_hdcp_key_probe(ctx); | |
| 842 | + if (ret) { | |
| 843 | + dev_dbg(dev, "no key found, not to do hdcp\n"); | |
| 844 | + return ret; | |
| 845 | + } | |
| 846 | + | |
| 847 | + /* Read downstream capability */ | |
| 848 | + anx7625_aux_dpcd_read(ctx, 0x68028, 1, &bcap); | |
| 849 | + if (!(bcap & 0x01)) { | |
| 850 | + pr_warn("downstream not support HDCP 1.4, cap(%x).\n", bcap); | |
| 851 | + return 0; | |
| 852 | + } | |
| 853 | + | |
| 854 | + dev_dbg(dev, "enable HDCP 1.4\n"); | |
| 855 | + | |
| 856 | + /* First clear HDCP state */ | |
| 857 | + ret = anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | |
| 858 | + TX_HDCP_CTRL0, | |
| 859 | + KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN); | |
| 860 | + usleep_range(1000, 1100); | |
| 861 | + /* Second clear HDCP state */ | |
| 862 | + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | |
| 863 | + TX_HDCP_CTRL0, | |
| 864 | + KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN); | |
| 865 | + | |
| 866 | + /* Set time for waiting KSVR */ | |
| 867 | + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | |
| 868 | + SP_TX_WAIT_KSVR_TIME, 0xc8); | |
| 869 | + /* Set time for waiting R0 */ | |
| 870 | + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | |
| 871 | + SP_TX_WAIT_R0_TIME, 0xb0); | |
| 872 | + ret |= anx7625_hdcp_key_load(ctx); | |
| 873 | + if (ret) { | |
| 874 | + pr_warn("prepare HDCP key failed.\n"); | |
| 875 | + return ret; | |
| 876 | + } | |
| 877 | + | |
| 878 | + ret = anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xee, 0x20); | |
| 879 | + | |
| 880 | + /* Try auth flag */ | |
| 881 | + ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10); | |
| 882 | + /* Interrupt for DRM */ | |
| 883 | + ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01); | |
| 884 | + if (ret < 0) | |
| 885 | + dev_err(dev, "fail to enable HDCP\n"); | |
| 886 | + | |
| 887 | + return anx7625_write_or(ctx, ctx->i2c.tx_p0_client, | |
| 888 | + TX_HDCP_CTRL0, HARD_AUTH_EN); | |
| 889 | +} | |
| 890 | + | |
| 672 | 891 | static void anx7625_dp_start(struct anx7625_data *ctx) |
| 673 | 892 | { |
| 674 | 893 | int ret; |
| @@ -679,6 +898,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx) · 4 unmodified lines | ||
| 679 | 898 | return; |
| 680 | 899 | } |
| 681 | 900 | |
| 901 | + /* Disable HDCP */ | |
| 902 | + anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f); | |
| 903 | + | |
| 682 | 904 | if (ctx->pdata.is_dpi) |
| 683 | 905 | ret = anx7625_dpi_config(ctx); |
| 684 | 906 | else |
| @@ -686,6 +908,10 @@ static void anx7625_dp_start(struct anx7625_data *ctx) · 1 unmodified line | ||
| 686 | 908 | |
| 687 | 909 | if (ret < 0) |
| 688 | 910 | DRM_DEV_ERROR(dev, "MIPI phy setup error.\n"); |
| 911 | + | |
| 912 | + ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; | |
| 913 | + | |
| 914 | + ctx->dp_en = 1; | |
| 689 | 915 | } |
| 690 | 916 | |
| 691 | 917 | static void anx7625_dp_stop(struct anx7625_data *ctx) |
| @@ -705,6 +931,10 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) · 13 unmodified lines | ||
| 705 | 931 | ret |= anx7625_video_mute_control(ctx, 1); |
| 706 | 932 | if (ret < 0) |
| 707 | 933 | DRM_DEV_ERROR(dev, "IO error : mute video fail\n"); |
| 934 | + | |
| 935 | + ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; | |
| 936 | + | |
| 937 | + ctx->dp_en = 0; | |
| 708 | 938 | } |
| 709 | 939 | |
| 710 | 940 | static int sp_tx_rst_aux(struct anx7625_data *ctx) |
| @@ -1098,9 +1328,18 @@ static void anx7625_init_gpio(struct anx7625_data *platform) · 387 unmodified lines | ||
| 1098 | 1328 | /* Gpio for chip power enable */ |
| 1099 | 1329 | platform->pdata.gpio_p_on = |
| 1100 | 1330 | devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); |
| 1331 | + if (IS_ERR_OR_NULL(platform->pdata.gpio_p_on)) { | |
| 1332 | + DRM_DEV_DEBUG_DRIVER(dev, "no enable gpio found\n"); | |
| 1333 | + platform->pdata.gpio_p_on = NULL; | |
| 1334 | + } | |
| 1335 | + | |
| 1101 | 1336 | /* Gpio for chip reset */ |
| 1102 | 1337 | platform->pdata.gpio_reset = |
| 1103 | 1338 | devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
| 1339 | + if (IS_ERR_OR_NULL(platform->pdata.gpio_reset)) { | |
| 1340 | + DRM_DEV_DEBUG_DRIVER(dev, "no reset gpio found\n"); | |
| 1341 | + platform->pdata.gpio_reset = NULL; | |
| 1342 | + } | |
| 1104 | 1343 | |
| 1105 | 1344 | if (platform->pdata.gpio_p_on && platform->pdata.gpio_reset) { |
| 1106 | 1345 | platform->pdata.low_power_mode = 1; |
| @@ -1601,9 +1840,27 @@ static int anx7625_audio_hook_plugged_cb(struct device *dev, void *data, · 494 unmodified lines | ||
| 1601 | 1840 | return 0; |
| 1602 | 1841 | } |
| 1603 | 1842 | |
| 1843 | +static int anx7625_audio_get_eld(struct device *dev, void *data, | |
| 1844 | + u8 *buf, size_t len) | |
| 1845 | +{ | |
| 1846 | + struct anx7625_data *ctx = dev_get_drvdata(dev); | |
| 1847 | + | |
| 1848 | + if (!ctx->connector) { | |
| 1849 | + dev_err(dev, "connector not initial\n"); | |
| 1850 | + return -EINVAL; | |
| 1851 | + } | |
| 1852 | + | |
| 1853 | + dev_dbg(dev, "audio copy eld\n"); | |
| 1854 | + memcpy(buf, ctx->connector->eld, | |
| 1855 | + min(sizeof(ctx->connector->eld), len)); | |
| 1856 | + | |
| 1857 | + return 0; | |
| 1858 | +} | |
| 1859 | + | |
| 1604 | 1860 | static const struct hdmi_codec_ops anx7625_codec_ops = { |
| 1605 | 1861 | .hw_params = anx7625_audio_hw_params, |
| 1606 | 1862 | .audio_shutdown = anx7625_audio_shutdown, |
| 1863 | + .get_eld = anx7625_audio_get_eld, | |
| 1607 | 1864 | .get_dai_id = anx7625_hdmi_i2s_get_dai_id, |
| 1608 | 1865 | .hook_plugged_cb = anx7625_audio_hook_plugged_cb, |
| 1609 | 1866 | }; |
| @@ -1660,7 +1917,7 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) · 50 unmodified lines | ||
| 1660 | 1917 | host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node); |
| 1661 | 1918 | if (!host) { |
| 1662 | 1919 | DRM_DEV_ERROR(dev, "fail to find dsi host.\n"); |
| 1663 | − return -EINVAL; | |
| 1920 | + return -EPROBE_DEFER; | |
| 1664 | 1921 | } |
| 1665 | 1922 | |
| 1666 | 1923 | dsi = devm_mipi_dsi_device_register_full(dev, host, &info); |
| @@ -1688,6 +1945,83 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) · 21 unmodified lines | ||
| 1688 | 1945 | return 0; |
| 1689 | 1946 | } |
| 1690 | 1947 | |
| 1948 | +static void hdcp_check_work_func(struct work_struct *work) | |
| 1949 | +{ | |
| 1950 | + u8 status; | |
| 1951 | + struct delayed_work *dwork; | |
| 1952 | + struct anx7625_data *ctx; | |
| 1953 | + struct device *dev; | |
| 1954 | + struct drm_device *drm_dev; | |
| 1955 | + | |
| 1956 | + dwork = to_delayed_work(work); | |
| 1957 | + ctx = container_of(dwork, struct anx7625_data, hdcp_work); | |
| 1958 | + dev = &ctx->client->dev; | |
| 1959 | + | |
| 1960 | + if (!ctx->connector) { | |
| 1961 | + dev_err(dev, "HDCP connector is null!"); | |
| 1962 | + return; | |
| 1963 | + } | |
| 1964 | + | |
| 1965 | + drm_dev = ctx->connector->dev; | |
| 1966 | + drm_modeset_lock(&drm_dev->mode_config.connection_mutex, NULL); | |
| 1967 | + mutex_lock(&ctx->hdcp_wq_lock); | |
| 1968 | + | |
| 1969 | + status = anx7625_reg_read(ctx, ctx->i2c.tx_p0_client, 0); | |
| 1970 | + dev_dbg(dev, "sink HDCP status check: %.02x\n", status); | |
| 1971 | + if (status & BIT(1)) { | |
| 1972 | + ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_ENABLED; | |
| 1973 | + drm_hdcp_update_content_protection(ctx->connector, | |
| 1974 | + ctx->hdcp_cp); | |
| 1975 | + dev_dbg(dev, "update CP to ENABLE\n"); | |
| 1976 | + } | |
| 1977 | + | |
| 1978 | + mutex_unlock(&ctx->hdcp_wq_lock); | |
| 1979 | + drm_modeset_unlock(&drm_dev->mode_config.connection_mutex); | |
| 1980 | +} | |
| 1981 | + | |
| 1982 | +static int anx7625_connector_atomic_check(struct anx7625_data *ctx, | |
| 1983 | + struct drm_connector_state *state) | |
| 1984 | +{ | |
| 1985 | + struct device *dev = &ctx->client->dev; | |
| 1986 | + int cp; | |
| 1987 | + | |
| 1988 | + dev_dbg(dev, "hdcp state check\n"); | |
| 1989 | + cp = state->content_protection; | |
| 1990 | + | |
| 1991 | + if (cp == ctx->hdcp_cp) | |
| 1992 | + return 0; | |
| 1993 | + | |
| 1994 | + if (cp == DRM_MODE_CONTENT_PROTECTION_DESIRED) { | |
| 1995 | + if (ctx->dp_en) { | |
| 1996 | + dev_dbg(dev, "enable HDCP\n"); | |
| 1997 | + anx7625_hdcp_enable(ctx); | |
| 1998 | + | |
| 1999 | + queue_delayed_work(ctx->hdcp_workqueue, | |
| 2000 | + &ctx->hdcp_work, | |
| 2001 | + msecs_to_jiffies(2000)); | |
| 2002 | + } | |
| 2003 | + } | |
| 2004 | + | |
| 2005 | + if (cp == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { | |
| 2006 | + if (ctx->hdcp_cp != DRM_MODE_CONTENT_PROTECTION_ENABLED) { | |
| 2007 | + dev_err(dev, "current CP is not ENABLED\n"); | |
| 2008 | + return -EINVAL; | |
| 2009 | + } | |
| 2010 | + anx7625_hdcp_disable(ctx); | |
| 2011 | + ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; | |
| 2012 | + drm_hdcp_update_content_protection(ctx->connector, | |
| 2013 | + ctx->hdcp_cp); | |
| 2014 | + dev_dbg(dev, "update CP to UNDESIRE\n"); | |
| 2015 | + } | |
| 2016 | + | |
| 2017 | + if (cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) { | |
| 2018 | + dev_err(dev, "Userspace illegal set to PROTECTION ENABLE\n"); | |
| 2019 | + return -EINVAL; | |
| 2020 | + } | |
| 2021 | + | |
| 2022 | + return 0; | |
| 2023 | +} | |
| 2024 | + | |
| 1691 | 2025 | static int anx7625_bridge_attach(struct drm_bridge *bridge, |
| 1692 | 2026 | enum drm_bridge_attach_flags flags) |
| 1693 | 2027 | { |
| @@ -1902,25 +2236,57 @@ static bool anx7625_bridge_mode_fixup(struct drm_bridge *bridge, · 208 unmodified lines | ||
| 1902 | 2236 | return true; |
| 1903 | 2237 | } |
| 1904 | 2238 | |
| 1905 | −static void anx7625_bridge_enable(struct drm_bridge *bridge) | |
| 2239 | +static int anx7625_bridge_atomic_check(struct drm_bridge *bridge, | |
| 2240 | + struct drm_bridge_state *bridge_state, | |
| 2241 | + struct drm_crtc_state *crtc_state, | |
| 2242 | + struct drm_connector_state *conn_state) | |
| 2243 | +{ | |
| 2244 | + struct anx7625_data *ctx = bridge_to_anx7625(bridge); | |
| 2245 | + struct device *dev = &ctx->client->dev; | |
| 2246 | + | |
| 2247 | + dev_dbg(dev, "drm bridge atomic check\n"); | |
| 2248 | + | |
| 2249 | + anx7625_bridge_mode_fixup(bridge, &crtc_state->mode, | |
| 2250 | + &crtc_state->adjusted_mode); | |
| 2251 | + | |
| 2252 | + return anx7625_connector_atomic_check(ctx, conn_state); | |
| 2253 | +} | |
| 2254 | + | |
| 2255 | +static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge, | |
| 2256 | + struct drm_bridge_state *state) | |
| 1906 | 2257 | { |
| 1907 | 2258 | struct anx7625_data *ctx = bridge_to_anx7625(bridge); |
| 1908 | 2259 | struct device *dev = &ctx->client->dev; |
| 2260 | + struct drm_connector *connector; | |
| 1909 | 2261 | |
| 1910 | − DRM_DEV_DEBUG_DRIVER(dev, "drm enable\n"); | |
| 2262 | + dev_dbg(dev, "drm atomic enable\n"); | |
| 2263 | + | |
| 2264 | + if (!bridge->encoder) { | |
| 2265 | + dev_err(dev, "Parent encoder object not found"); | |
| 2266 | + return; | |
| 2267 | + } | |
| 2268 | + | |
| 2269 | + connector = drm_atomic_get_new_connector_for_encoder(state->base.state, | |
| 2270 | + bridge->encoder); | |
| 2271 | + if (!connector) | |
| 2272 | + return; | |
| 2273 | + | |
| 2274 | + ctx->connector = connector; | |
| 1911 | 2275 | |
| 1912 | 2276 | pm_runtime_get_sync(dev); |
| 1913 | 2277 | |
| 1914 | 2278 | anx7625_dp_start(ctx); |
| 1915 | 2279 | } |
| 1916 | 2280 | |
| 1917 | −static void anx7625_bridge_disable(struct drm_bridge *bridge) | |
| 2281 | +static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, | |
| 2282 | + struct drm_bridge_state *old) | |
| 1918 | 2283 | { |
| 1919 | 2284 | struct anx7625_data *ctx = bridge_to_anx7625(bridge); |
| 1920 | 2285 | struct device *dev = &ctx->client->dev; |
| 1921 | 2286 | |
| 1922 | − DRM_DEV_DEBUG_DRIVER(dev, "drm disable\n"); | |
| 2287 | + dev_dbg(dev, "drm atomic disable\n"); | |
| 1923 | 2288 | |
| 2289 | + ctx->connector = NULL; | |
| 1924 | 2290 | anx7625_dp_stop(ctx); |
| 1925 | 2291 | |
| 1926 | 2292 | pm_runtime_put_sync(dev); |
| @@ -1950,11 +2316,14 @@ static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge, · 23 unmodified lines | ||
| 1950 | 2316 | |
| 1951 | 2317 | static const struct drm_bridge_funcs anx7625_bridge_funcs = { |
| 1952 | 2318 | .attach = anx7625_bridge_attach, |
| 1953 | − .disable = anx7625_bridge_disable, | |
| 1954 | 2319 | .mode_valid = anx7625_bridge_mode_valid, |
| 1955 | 2320 | .mode_set = anx7625_bridge_mode_set, |
| 1956 | − .mode_fixup = anx7625_bridge_mode_fixup, | |
| 1957 | − .enable = anx7625_bridge_enable, | |
| 2321 | + .atomic_check = anx7625_bridge_atomic_check, | |
| 2322 | + .atomic_enable = anx7625_bridge_atomic_enable, | |
| 2323 | + .atomic_disable = anx7625_bridge_atomic_disable, | |
| 2324 | + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, | |
| 2325 | + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, | |
| 2326 | + .atomic_reset = drm_atomic_helper_bridge_reset, | |
| 1958 | 2327 | .detect = anx7625_bridge_detect, |
| 1959 | 2328 | .get_edid = anx7625_bridge_get_edid, |
| 1960 | 2329 | }; |
| @@ -1962,40 +2331,54 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = { · 1 unmodified line | ||
| 1962 | 2331 | static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx, |
| 1963 | 2332 | struct i2c_client *client) |
| 1964 | 2333 | { |
| 2334 | + int err = 0; | |
| 2335 | + | |
| 1965 | 2336 | ctx->i2c.tx_p0_client = i2c_new_dummy_device(client->adapter, |
| 1966 | 2337 | TX_P0_ADDR >> 1); |
| 1967 | − if (!ctx->i2c.tx_p0_client) | |
| 1968 | − return -ENOMEM; | |
| 2338 | + if (IS_ERR(ctx->i2c.tx_p0_client)) | |
| 2339 | + return PTR_ERR(ctx->i2c.tx_p0_client); | |
| 1969 | 2340 | |
| 1970 | 2341 | ctx->i2c.tx_p1_client = i2c_new_dummy_device(client->adapter, |
| 1971 | 2342 | TX_P1_ADDR >> 1); |
| 1972 | − if (!ctx->i2c.tx_p1_client) | |
| 2343 | + if (IS_ERR(ctx->i2c.tx_p1_client)) { | |
| 2344 | + err = PTR_ERR(ctx->i2c.tx_p1_client); | |
| 1973 | 2345 | goto free_tx_p0; |
| 2346 | + } | |
| 1974 | 2347 | |
| 1975 | 2348 | ctx->i2c.tx_p2_client = i2c_new_dummy_device(client->adapter, |
| 1976 | 2349 | TX_P2_ADDR >> 1); |
| 1977 | − if (!ctx->i2c.tx_p2_client) | |
| 2350 | + if (IS_ERR(ctx->i2c.tx_p2_client)) { | |
| 2351 | + err = PTR_ERR(ctx->i2c.tx_p2_client); | |
| 1978 | 2352 | goto free_tx_p1; |
| 2353 | + } | |
| 1979 | 2354 | |
| 1980 | 2355 | ctx->i2c.rx_p0_client = i2c_new_dummy_device(client->adapter, |
| 1981 | 2356 | RX_P0_ADDR >> 1); |
| 1982 | − if (!ctx->i2c.rx_p0_client) | |
| 2357 | + if (IS_ERR(ctx->i2c.rx_p0_client)) { | |
| 2358 | + err = PTR_ERR(ctx->i2c.rx_p0_client); | |
| 1983 | 2359 | goto free_tx_p2; |
| 2360 | + } | |
| 1984 | 2361 | |
| 1985 | 2362 | ctx->i2c.rx_p1_client = i2c_new_dummy_device(client->adapter, |
| 1986 | 2363 | RX_P1_ADDR >> 1); |
| 1987 | − if (!ctx->i2c.rx_p1_client) | |
| 2364 | + if (IS_ERR(ctx->i2c.rx_p1_client)) { | |
| 2365 | + err = PTR_ERR(ctx->i2c.rx_p1_client); | |
| 1988 | 2366 | goto free_rx_p0; |
| 2367 | + } | |
| 1989 | 2368 | |
| 1990 | 2369 | ctx->i2c.rx_p2_client = i2c_new_dummy_device(client->adapter, |
| 1991 | 2370 | RX_P2_ADDR >> 1); |
| 1992 | − if (!ctx->i2c.rx_p2_client) | |
| 2371 | + if (IS_ERR(ctx->i2c.rx_p2_client)) { | |
| 2372 | + err = PTR_ERR(ctx->i2c.rx_p2_client); | |
| 1993 | 2373 | goto free_rx_p1; |
| 2374 | + } | |
| 1994 | 2375 | |
| 1995 | 2376 | ctx->i2c.tcpc_client = i2c_new_dummy_device(client->adapter, |
| 1996 | 2377 | TCPC_INTERFACE_ADDR >> 1); |
| 1997 | − if (!ctx->i2c.tcpc_client) | |
| 2378 | + if (IS_ERR(ctx->i2c.tcpc_client)) { | |
| 2379 | + err = PTR_ERR(ctx->i2c.tcpc_client); | |
| 1998 | 2380 | goto free_rx_p2; |
| 2381 | + } | |
| 1999 | 2382 | |
| 2000 | 2383 | return 0; |
| 2001 | 2384 | |
| @@ -2012,7 +2395,7 @@ free_tx_p1: · 10 unmodified lines | ||
| 2012 | 2395 | free_tx_p0: |
| 2013 | 2396 | i2c_unregister_device(ctx->i2c.tx_p0_client); |
| 2014 | 2397 | |
| 2015 | − return -ENOMEM; | |
| 2398 | + return err; | |
| 2016 | 2399 | } |
| 2017 | 2400 | |
| 2018 | 2401 | static void anx7625_unregister_i2c_dummy_clients(struct anx7625_data *ctx) |
| @@ -2134,6 +2517,15 @@ static int anx7625_i2c_probe(struct i2c_client *client, · 115 unmodified lines | ||
| 2134 | 2517 | anx7625_init_gpio(platform); |
| 2135 | 2518 | |
| 2136 | 2519 | mutex_init(&platform->lock); |
| 2520 | + mutex_init(&platform->hdcp_wq_lock); | |
| 2521 | + | |
| 2522 | + INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func); | |
| 2523 | + platform->hdcp_workqueue = create_workqueue("hdcp workqueue"); | |
| 2524 | + if (!platform->hdcp_workqueue) { | |
| 2525 | + dev_err(dev, "fail to create work queue\n"); | |
| 2526 | + ret = -ENOMEM; | |
| 2527 | + goto free_platform; | |
| 2528 | + } | |
| 2137 | 2529 | |
| 2138 | 2530 | platform->pdata.intp_irq = client->irq; |
| 2139 | 2531 | if (platform->pdata.intp_irq) { |
| @@ -2143,7 +2535,7 @@ static int anx7625_i2c_probe(struct i2c_client *client, · 3 unmodified lines | ||
| 2143 | 2535 | if (!platform->workqueue) { |
| 2144 | 2536 | DRM_DEV_ERROR(dev, "fail to create work queue\n"); |
| 2145 | 2537 | ret = -ENOMEM; |
| 2146 | − goto free_platform; | |
| 2538 | + goto free_hdcp_wq; | |
| 2147 | 2539 | } |
| 2148 | 2540 | |
| 2149 | 2541 | ret = devm_request_threaded_irq(dev, platform->pdata.intp_irq, |
| @@ -2213,6 +2605,10 @@ free_wq: · 63 unmodified lines | ||
| 2213 | 2605 | if (platform->workqueue) |
| 2214 | 2606 | destroy_workqueue(platform->workqueue); |
| 2215 | 2607 | |
| 2608 | +free_hdcp_wq: | |
| 2609 | + if (platform->hdcp_workqueue) | |
| 2610 | + destroy_workqueue(platform->hdcp_workqueue); | |
| 2611 | + | |
| 2216 | 2612 | free_platform: |
| 2217 | 2613 | kfree(platform); |
| 2218 | 2614 | |
| @@ -2228,6 +2624,12 @@ static int anx7625_i2c_remove(struct i2c_client *client) · 9 unmodified lines | ||
| 2228 | 2624 | if (platform->pdata.intp_irq) |
| 2229 | 2625 | destroy_workqueue(platform->workqueue); |
| 2230 | 2626 | |
| 2627 | + if (platform->hdcp_workqueue) { | |
| 2628 | + cancel_delayed_work(&platform->hdcp_work); | |
| 2629 | + flush_workqueue(platform->workqueue); | |
| 2630 | + destroy_workqueue(platform->workqueue); | |
| 2631 | + } | |
| 2632 | + | |
| 2231 | 2633 | if (!platform->pdata.low_power_mode) |
| 2232 | 2634 | pm_runtime_put_sync_suspend(&client->dev); |
| 2233 | 2635 | |
| @@ -59,10 +59,23 @@ · 58 unmodified lines | ||
| 59 | 59 | |
| 60 | 60 | /***************************************************************/ |
| 61 | 61 | /* Register definition of device address 0x70 */ |
| 62 | −#define I2C_ADDR_70_DPTX 0x70 | |
| 63 | − | |
| 64 | −#define SP_TX_LINK_BW_SET_REG 0xA0 | |
| 65 | −#define SP_TX_LANE_COUNT_SET_REG 0xA1 | |
| 62 | +#define TX_HDCP_CTRL0 0x01 | |
| 63 | +#define STORE_AN BIT(7) | |
| 64 | +#define RX_REPEATER BIT(6) | |
| 65 | +#define RE_AUTHEN BIT(5) | |
| 66 | +#define SW_AUTH_OK BIT(4) | |
| 67 | +#define HARD_AUTH_EN BIT(3) | |
| 68 | +#define ENC_EN BIT(2) | |
| 69 | +#define BKSV_SRM_PASS BIT(1) | |
| 70 | +#define KSVLIST_VLD BIT(0) | |
| 71 | + | |
| 72 | +#define SP_TX_WAIT_R0_TIME 0x40 | |
| 73 | +#define SP_TX_WAIT_KSVR_TIME 0x42 | |
| 74 | +#define SP_TX_SYS_CTRL1_REG 0x80 | |
| 75 | +#define HDCP2TX_FW_EN BIT(4) | |
| 76 | + | |
| 77 | +#define SP_TX_LINK_BW_SET_REG 0xA0 | |
| 78 | +#define SP_TX_LANE_COUNT_SET_REG 0xA1 | |
| 66 | 79 | |
| 67 | 80 | #define M_VID_0 0xC0 |
| 68 | 81 | #define M_VID_1 0xC1 |
| @@ -71,6 +84,12 @@ · 2 unmodified lines | ||
| 71 | 84 | #define N_VID_1 0xC4 |
| 72 | 85 | #define N_VID_2 0xC5 |
| 73 | 86 | |
| 87 | +#define KEY_START_ADDR 0x9000 | |
| 88 | +#define KEY_RESERVED 416 | |
| 89 | + | |
| 90 | +#define HDCP14KEY_START_ADDR (KEY_START_ADDR + KEY_RESERVED) | |
| 91 | +#define HDCP14KEY_SIZE 624 | |
| 92 | + | |
| 74 | 93 | /***************************************************************/ |
| 75 | 94 | /* Register definition of device address 0x72 */ |
| 76 | 95 | #define AUX_RST 0x04 |
| @@ -155,9 +174,43 @@ · 78 unmodified lines | ||
| 155 | 174 | |
| 156 | 175 | #define I2C_ADDR_7E_FLASH_CONTROLLER 0x7E |
| 157 | 176 | |
| 177 | +#define R_BOOT_RETRY 0x00 | |
| 178 | +#define R_RAM_ADDR_H 0x01 | |
| 179 | +#define R_RAM_ADDR_L 0x02 | |
| 180 | +#define R_RAM_LEN_H 0x03 | |
| 181 | +#define R_RAM_LEN_L 0x04 | |
| 158 | 182 | #define FLASH_LOAD_STA 0x05 |
| 159 | 183 | #define FLASH_LOAD_STA_CHK BIT(7) |
| 160 | 184 | |
| 185 | +#define R_RAM_CTRL 0x05 | |
| 186 | +/* bit positions */ | |
| 187 | +#define FLASH_DONE BIT(7) | |
| 188 | +#define BOOT_LOAD_DONE BIT(6) | |
| 189 | +#define CRC_OK BIT(5) | |
| 190 | +#define LOAD_DONE BIT(4) | |
| 191 | +#define O_RW_DONE BIT(3) | |
| 192 | +#define FUSE_BUSY BIT(2) | |
| 193 | +#define DECRYPT_EN BIT(1) | |
| 194 | +#define LOAD_START BIT(0) | |
| 195 | + | |
| 196 | +#define FLASH_ADDR_HIGH 0x0F | |
| 197 | +#define FLASH_ADDR_LOW 0x10 | |
| 198 | +#define FLASH_LEN_HIGH 0x31 | |
| 199 | +#define FLASH_LEN_LOW 0x32 | |
| 200 | +#define R_FLASH_RW_CTRL 0x33 | |
| 201 | +/* bit positions */ | |
| 202 | +#define READ_DELAY_SELECT BIT(7) | |
| 203 | +#define GENERAL_INSTRUCTION_EN BIT(6) | |
| 204 | +#define FLASH_ERASE_EN BIT(5) | |
| 205 | +#define RDID_READ_EN BIT(4) | |
| 206 | +#define REMS_READ_EN BIT(3) | |
| 207 | +#define WRITE_STATUS_EN BIT(2) | |
| 208 | +#define FLASH_READ BIT(1) | |
| 209 | +#define FLASH_WRITE BIT(0) | |
| 210 | + | |
| 211 | +#define FLASH_BUF_BASE_ADDR 0x60 | |
| 212 | +#define FLASH_BUF_LEN 0x20 | |
| 213 | + | |
| 161 | 214 | #define XTAL_FRQ_SEL 0x3F |
| 162 | 215 | /* bit field positions */ |
| 163 | 216 | #define XTAL_FRQ_SEL_POS 5 |
| @@ -184,10 +237,15 @@ · 20 unmodified lines | ||
| 184 | 237 | #define AP_AUX_CTRL_ADDRONLY 0x20 |
| 185 | 238 | |
| 186 | 239 | #define AP_AUX_BUFF_START 0x15 |
| 187 | −#define PIXEL_CLOCK_L 0x25 | |
| 188 | −#define PIXEL_CLOCK_H 0x26 | |
| 240 | +#define PIXEL_CLOCK_L 0x25 | |
| 241 | +#define PIXEL_CLOCK_H 0x26 | |
| 242 | + | |
| 243 | +#define AP_AUX_COMMAND 0x27 /* com+len */ | |
| 244 | +#define LENGTH_SHIFT 4 | |
| 245 | +#define DPCD_READ 0x09 | |
| 246 | +#define DPCD_WRITE 0x08 | |
| 247 | +#define DPCD_CMD(len, cmd) ((((len) - 1) << LENGTH_SHIFT) | (cmd)) | |
| 189 | 248 | |
| 190 | −#define AP_AUX_COMMAND 0x27 /* com+len */ | |
| 191 | 249 | /* Bit 0&1: 3D video structure */ |
| 192 | 250 | /* 0x01: frame packing, 0x02:Line alternative, 0x03:Side-by-side(full) */ |
| 193 | 251 | #define AP_AV_STATUS 0x28 |
| @@ -392,21 +450,29 @@ struct anx7625_data { · 198 unmodified lines | ||
| 392 | 450 | struct platform_device *audio_pdev; |
| 393 | 451 | int hpd_status; |
| 394 | 452 | int hpd_high_cnt; |
| 453 | + int dp_en; | |
| 454 | + int hdcp_cp; | |
| 395 | 455 | /* Lock for work queue */ |
| 396 | 456 | struct mutex lock; |
| 397 | 457 | struct i2c_client *client; |
| 398 | 458 | struct anx7625_i2c_client i2c; |
| 399 | 459 | struct i2c_client *last_client; |
| 460 | + struct timer_list hdcp_timer; | |
| 400 | 461 | struct s_edid_data slimport_edid_p; |
| 401 | 462 | struct device *codec_dev; |
| 402 | 463 | hdmi_codec_plugged_cb plugged_cb; |
| 403 | 464 | struct work_struct work; |
| 404 | 465 | struct workqueue_struct *workqueue; |
| 466 | + struct delayed_work hdcp_work; | |
| 467 | + struct workqueue_struct *hdcp_workqueue; | |
| 468 | + /* Lock for hdcp work queue */ | |
| 469 | + struct mutex hdcp_wq_lock; | |
| 405 | 470 | char edid_block; |
| 406 | 471 | struct display_timing dt; |
| 407 | 472 | u8 display_timing_valid; |
| 408 | 473 | struct drm_bridge bridge; |
| 409 | 474 | u8 bridge_attached; |
| 475 | + struct drm_connector *connector; | |
| 410 | 476 | struct mipi_dsi_device *dsi; |
| 411 | 477 | }; |
| 412 | 478 | |
| @@ -1,6 +1,7 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | 2 | config DRM_CDNS_MHDP8546 |
| 3 | 3 | tristate "Cadence DPI/DP bridge" |
| 4 | + select DRM_DP_HELPER | |
| 4 | 5 | select DRM_KMS_HELPER |
| 5 | 6 | select DRM_PANEL_BRIDGE |
| 6 | 7 | depends on OF |
| @@ -41,7 +41,7 @@ · 40 unmodified lines | ||
| 41 | 41 | #include <drm/drm_bridge.h> |
| 42 | 42 | #include <drm/drm_connector.h> |
| 43 | 43 | #include <drm/drm_crtc_helper.h> |
| 44 | −#include <drm/drm_dp_helper.h> | |
| 44 | +#include <drm/dp/drm_dp_helper.h> | |
| 45 | 45 | #include <drm/drm_hdcp.h> |
| 46 | 46 | #include <drm/drm_modeset_helper_vtables.h> |
| 47 | 47 | #include <drm/drm_print.h> |
| @@ -1553,13 +1553,13 @@ static u32 cdns_mhdp_get_bpp(struct cdns_mhdp_display_fmt *fmt) · 1505 unmodified lines | ||
| 1553 | 1553 | |
| 1554 | 1554 | switch (fmt->color_format) { |
| 1555 | 1555 | case DRM_COLOR_FORMAT_RGB444: |
| 1556 | − case DRM_COLOR_FORMAT_YCRCB444: | |
| 1556 | + case DRM_COLOR_FORMAT_YCBCR444: | |
| 1557 | 1557 | bpp = fmt->bpc * 3; |
| 1558 | 1558 | break; |
| 1559 | − case DRM_COLOR_FORMAT_YCRCB422: | |
| 1559 | + case DRM_COLOR_FORMAT_YCBCR422: | |
| 1560 | 1560 | bpp = fmt->bpc * 2; |
| 1561 | 1561 | break; |
| 1562 | − case DRM_COLOR_FORMAT_YCRCB420: | |
| 1562 | + case DRM_COLOR_FORMAT_YCBCR420: | |
| 1563 | 1563 | bpp = fmt->bpc * 3 / 2; |
| 1564 | 1564 | break; |
| 1565 | 1565 | default: |
| @@ -1767,8 +1767,8 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, · 201 unmodified lines | ||
| 1767 | 1767 | * If YCBCR supported and stream not SD, use ITU709 |
| 1768 | 1768 | * Need to handle ITU version with YCBCR420 when supported |
| 1769 | 1769 | */ |
| 1770 | − if ((pxlfmt == DRM_COLOR_FORMAT_YCRCB444 || | |
| 1771 | − pxlfmt == DRM_COLOR_FORMAT_YCRCB422) && mode->crtc_vdisplay >= 720) | |
| 1770 | + if ((pxlfmt == DRM_COLOR_FORMAT_YCBCR444 || | |
| 1771 | + pxlfmt == DRM_COLOR_FORMAT_YCBCR422) && mode->crtc_vdisplay >= 720) | |
| 1772 | 1772 | misc0 = DP_YCBCR_COEFFICIENTS_ITU709; |
| 1773 | 1773 | |
| 1774 | 1774 | bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt); |
| @@ -1778,15 +1778,15 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, · 3 unmodified lines | ||
| 1778 | 1778 | pxl_repr = CDNS_DP_FRAMER_RGB << CDNS_DP_FRAMER_PXL_FORMAT; |
| 1779 | 1779 | misc0 |= DP_COLOR_FORMAT_RGB; |
| 1780 | 1780 | break; |
| 1781 | − case DRM_COLOR_FORMAT_YCRCB444: | |
| 1781 | + case DRM_COLOR_FORMAT_YCBCR444: | |
| 1782 | 1782 | pxl_repr = CDNS_DP_FRAMER_YCBCR444 << CDNS_DP_FRAMER_PXL_FORMAT; |
| 1783 | 1783 | misc0 |= DP_COLOR_FORMAT_YCbCr444 | DP_TEST_DYNAMIC_RANGE_CEA; |
| 1784 | 1784 | break; |
| 1785 | − case DRM_COLOR_FORMAT_YCRCB422: | |
| 1785 | + case DRM_COLOR_FORMAT_YCBCR422: | |
| 1786 | 1786 | pxl_repr = CDNS_DP_FRAMER_YCBCR422 << CDNS_DP_FRAMER_PXL_FORMAT; |
| 1787 | 1787 | misc0 |= DP_COLOR_FORMAT_YCbCr422 | DP_TEST_DYNAMIC_RANGE_CEA; |
| 1788 | 1788 | break; |
| 1789 | − case DRM_COLOR_FORMAT_YCRCB420: | |
| 1789 | + case DRM_COLOR_FORMAT_YCBCR420: | |
| 1790 | 1790 | pxl_repr = CDNS_DP_FRAMER_YCBCR420 << CDNS_DP_FRAMER_PXL_FORMAT; |
| 1791 | 1791 | break; |
| 1792 | 1792 | default: |
| @@ -1882,7 +1882,7 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, · 89 unmodified lines | ||
| 1882 | 1882 | if (mhdp->display_fmt.y_only) |
| 1883 | 1883 | misc1 |= CDNS_DP_TEST_COLOR_FORMAT_RAW_Y_ONLY; |
| 1884 | 1884 | /* Use VSC SDP for Y420 */ |
| 1885 | − if (pxlfmt == DRM_COLOR_FORMAT_YCRCB420) | |
| 1885 | + if (pxlfmt == DRM_COLOR_FORMAT_YCBCR420) | |
| 1886 | 1886 | misc1 = CDNS_DP_TEST_VSC_SDP; |
| 1887 | 1887 | |
| 1888 | 1888 | cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_MISC(stream_id), |
| @@ -17,7 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | #include <drm/drm_bridge.h> |
| 19 | 19 | #include <drm/drm_connector.h> |
| 20 | −#include <drm/drm_dp_helper.h> | |
| 20 | +#include <drm/dp/drm_dp_helper.h> | |
| 21 | 21 | |
| 22 | 22 | struct clk; |
| 23 | 23 | struct device; |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | * Author: Jagan Teki <jagan@amarulasolutions.com> |
| 5 | 5 | */ |
| 6 | 6 | |
| 7 | +#include <drm/drm_atomic_helper.h> | |
| 7 | 8 | #include <drm/drm_of.h> |
| 8 | 9 | #include <drm/drm_print.h> |
| 9 | 10 | #include <drm/drm_mipi_dsi.h> |
| @@ -30,6 +31,7 @@ · 20 unmodified lines | ||
| 30 | 31 | struct chipone { |
| 31 | 32 | struct device *dev; |
| 32 | 33 | struct drm_bridge bridge; |
| 34 | + struct drm_display_mode mode; | |
| 33 | 35 | struct drm_bridge *panel_bridge; |
| 34 | 36 | struct gpio_desc *enable_gpio; |
| 35 | 37 | struct regulator *vdd1; |
| @@ -42,11 +44,6 @@ static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge) · 6 unmodified lines | ||
| 42 | 44 | return container_of(bridge, struct chipone, bridge); |
| 43 | 45 | } |
| 44 | 46 | |
| 45 | −static struct drm_display_mode *bridge_to_mode(struct drm_bridge *bridge) | |
| 46 | −{ | |
| 47 | − return &bridge->encoder->crtc->state->adjusted_mode; | |
| 48 | −} | |
| 49 | − | |
| 50 | 47 | static inline int chipone_dsi_write(struct chipone *icn, const void *seq, |
| 51 | 48 | size_t len) |
| 52 | 49 | { |
| @@ -61,10 +58,11 @@ static inline int chipone_dsi_write(struct chipone *icn, const void *seq, · 8 unmodified lines | ||
| 61 | 58 | chipone_dsi_write(icn, d, ARRAY_SIZE(d)); \ |
| 62 | 59 | } |
| 63 | 60 | |
| 64 | −static void chipone_enable(struct drm_bridge *bridge) | |
| 61 | +static void chipone_atomic_enable(struct drm_bridge *bridge, | |
| 62 | + struct drm_bridge_state *old_bridge_state) | |
| 65 | 63 | { |
| 66 | 64 | struct chipone *icn = bridge_to_chipone(bridge); |
| 67 | − struct drm_display_mode *mode = bridge_to_mode(bridge); | |
| 65 | + struct drm_display_mode *mode = &icn->mode; | |
| 68 | 66 | |
| 69 | 67 | ICN6211_DSI(icn, 0x7a, 0xc1); |
| 70 | 68 | |
| @@ -114,7 +112,8 @@ static void chipone_enable(struct drm_bridge *bridge) · 43 unmodified lines | ||
| 114 | 112 | usleep_range(10000, 11000); |
| 115 | 113 | } |
| 116 | 114 | |
| 117 | −static void chipone_pre_enable(struct drm_bridge *bridge) | |
| 115 | +static void chipone_atomic_pre_enable(struct drm_bridge *bridge, | |
| 116 | + struct drm_bridge_state *old_bridge_state) | |
| 118 | 117 | { |
| 119 | 118 | struct chipone *icn = bridge_to_chipone(bridge); |
| 120 | 119 | int ret; |
| @@ -145,7 +144,8 @@ static void chipone_pre_enable(struct drm_bridge *bridge) · 24 unmodified lines | ||
| 145 | 144 | usleep_range(10000, 11000); |
| 146 | 145 | } |
| 147 | 146 | |
| 148 | −static void chipone_post_disable(struct drm_bridge *bridge) | |
| 147 | +static void chipone_atomic_post_disable(struct drm_bridge *bridge, | |
| 148 | + struct drm_bridge_state *old_bridge_state) | |
| 149 | 149 | { |
| 150 | 150 | struct chipone *icn = bridge_to_chipone(bridge); |
| 151 | 151 | |
| @@ -161,6 +161,15 @@ static void chipone_post_disable(struct drm_bridge *bridge) · 9 unmodified lines | ||
| 161 | 161 | gpiod_set_value(icn->enable_gpio, 0); |
| 162 | 162 | } |
| 163 | 163 | |
| 164 | +static void chipone_mode_set(struct drm_bridge *bridge, | |
| 165 | + const struct drm_display_mode *mode, | |
| 166 | + const struct drm_display_mode *adjusted_mode) | |
| 167 | +{ | |
| 168 | + struct chipone *icn = bridge_to_chipone(bridge); | |
| 169 | + | |
| 170 | + drm_mode_copy(&icn->mode, adjusted_mode); | |
| 171 | +} | |
| 172 | + | |
| 164 | 173 | static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) |
| 165 | 174 | { |
| 166 | 175 | struct chipone *icn = bridge_to_chipone(bridge); |
| @@ -169,10 +178,14 @@ static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flag · 2 unmodified lines | ||
| 169 | 178 | } |
| 170 | 179 | |
| 171 | 180 | static const struct drm_bridge_funcs chipone_bridge_funcs = { |
| 172 | − .attach = chipone_attach, | |
| 173 | − .post_disable = chipone_post_disable, | |
| 174 | − .pre_enable = chipone_pre_enable, | |
| 175 | − .enable = chipone_enable, | |
| 181 | + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, | |
| 182 | + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, | |
| 183 | + .atomic_reset = drm_atomic_helper_bridge_reset, | |
| 184 | + .atomic_pre_enable = chipone_atomic_pre_enable, | |
| 185 | + .atomic_enable = chipone_atomic_enable, | |
| 186 | + .atomic_post_disable = chipone_atomic_post_disable, | |
| 187 | + .mode_set = chipone_mode_set, | |
| 188 | + .attach = chipone_attach, | |
| 176 | 189 | }; |
| 177 | 190 | |
| 178 | 191 | static int chipone_parse_dt(struct chipone *icn) |
| @@ -936,9 +936,6 @@ static int it66121_probe(struct i2c_client *client, · 935 unmodified lines | ||
| 936 | 936 | return -EPROBE_DEFER; |
| 937 | 937 | } |
| 938 | 938 | |
| 939 | − if (!ctx->next_bridge) | |
| 940 | − return -EPROBE_DEFER; | |
| 941 | − | |
| 942 | 939 | i2c_set_clientdata(client, ctx); |
| 943 | 940 | mutex_init(&ctx->lock); |
| 944 | 941 | |
| @@ -1090,7 +1090,7 @@ static int lt9611_probe(struct i2c_client *client, · 1089 unmodified lines | ||
| 1090 | 1090 | if (!lt9611) |
| 1091 | 1091 | return -ENOMEM; |
| 1092 | 1092 | |
| 1093 | − lt9611->dev = &client->dev; | |
| 1093 | + lt9611->dev = dev; | |
| 1094 | 1094 | lt9611->client = client; |
| 1095 | 1095 | lt9611->sleep = false; |
| 1096 | 1096 | |
| @@ -1100,7 +1100,7 @@ static int lt9611_probe(struct i2c_client *client, · 3 unmodified lines | ||
| 1100 | 1100 | return PTR_ERR(lt9611->regmap); |
| 1101 | 1101 | } |
| 1102 | 1102 | |
| 1103 | − ret = lt9611_parse_dt(&client->dev, lt9611); | |
| 1103 | + ret = lt9611_parse_dt(dev, lt9611); | |
| 1104 | 1104 | if (ret) { |
| 1105 | 1105 | dev_err(dev, "failed to parse device tree\n"); |
| 1106 | 1106 | return ret; |
| @@ -860,7 +860,7 @@ static int lt9611uxc_probe(struct i2c_client *client, · 859 unmodified lines | ||
| 860 | 860 | if (!lt9611uxc) |
| 861 | 861 | return -ENOMEM; |
| 862 | 862 | |
| 863 | − lt9611uxc->dev = &client->dev; | |
| 863 | + lt9611uxc->dev = dev; | |
| 864 | 864 | lt9611uxc->client = client; |
| 865 | 865 | mutex_init(<9611uxc->ocm_lock); |
| 866 | 866 | |
| @@ -870,7 +870,7 @@ static int lt9611uxc_probe(struct i2c_client *client, · 3 unmodified lines | ||
| 870 | 870 | return PTR_ERR(lt9611uxc->regmap); |
| 871 | 871 | } |
| 872 | 872 | |
| 873 | − ret = lt9611uxc_parse_dt(&client->dev, lt9611uxc); | |
| 873 | + ret = lt9611uxc_parse_dt(dev, lt9611uxc); | |
| 874 | 874 | if (ret) { |
| 875 | 875 | dev_err(dev, "failed to parse device tree\n"); |
| 876 | 876 | return ret; |
| @@ -65,7 +65,6 @@ struct nwl_dsi_transfer { · 64 unmodified lines | ||
| 65 | 65 | struct nwl_dsi { |
| 66 | 66 | struct drm_bridge bridge; |
| 67 | 67 | struct mipi_dsi_host dsi_host; |
| 68 | − struct drm_bridge *panel_bridge; | |
| 69 | 68 | struct device *dev; |
| 70 | 69 | struct phy *phy; |
| 71 | 70 | union phy_configure_opts phy_cfg; |
| @@ -924,13 +923,11 @@ static int nwl_dsi_bridge_attach(struct drm_bridge *bridge, · 852 unmodified lines | ||
| 924 | 923 | if (IS_ERR(panel_bridge)) |
| 925 | 924 | return PTR_ERR(panel_bridge); |
| 926 | 925 | } |
| 927 | − dsi->panel_bridge = panel_bridge; | |
| 928 | 926 | |
| 929 | − if (!dsi->panel_bridge) | |
| 927 | + if (!panel_bridge) | |
| 930 | 928 | return -EPROBE_DEFER; |
| 931 | 929 | |
| 932 | − return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge, | |
| 933 | − flags); | |
| 930 | + return drm_bridge_attach(bridge->encoder, panel_bridge, bridge, flags); | |
| 934 | 931 | } |
| 935 | 932 | |
| 936 | 933 | static void nwl_dsi_bridge_detach(struct drm_bridge *bridge) |
| @@ -1206,6 +1203,7 @@ static int nwl_dsi_probe(struct platform_device *pdev) · 269 unmodified lines | ||
| 1206 | 1203 | |
| 1207 | 1204 | ret = nwl_dsi_select_input(dsi); |
| 1208 | 1205 | if (ret < 0) { |
| 1206 | + pm_runtime_disable(dev); | |
| 1209 | 1207 | mipi_dsi_host_unregister(&dsi->dsi_host); |
| 1210 | 1208 | return ret; |
| 1211 | 1209 | } |
| @@ -14,8 +14,8 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/regulator/consumer.h> |
| 15 | 15 | |
| 16 | 16 | #include <drm/drm_bridge.h> |
| 17 | −#include <drm/drm_dp_aux_bus.h> | |
| 18 | −#include <drm/drm_dp_helper.h> | |
| 17 | +#include <drm/dp/drm_dp_aux_bus.h> | |
| 18 | +#include <drm/dp/drm_dp_helper.h> | |
| 19 | 19 | #include <drm/drm_mipi_dsi.h> |
| 20 | 20 | #include <drm/drm_of.h> |
| 21 | 21 | #include <drm/drm_panel.h> |
| @@ -102,6 +102,7 @@ struct ps8640 { · 80 unmodified lines | ||
| 102 | 102 | struct regulator_bulk_data supplies[2]; |
| 103 | 103 | struct gpio_desc *gpio_reset; |
| 104 | 104 | struct gpio_desc *gpio_powerdown; |
| 105 | + struct device_link *link; | |
| 105 | 106 | bool pre_enabled; |
| 106 | 107 | }; |
| 107 | 108 | |
| @@ -456,14 +457,36 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge, · 348 unmodified lines | ||
| 456 | 457 | return ret; |
| 457 | 458 | } |
| 458 | 459 | |
| 460 | + ps_bridge->link = device_link_add(bridge->dev->dev, dev, DL_FLAG_STATELESS); | |
| 461 | + if (!ps_bridge->link) { | |
| 462 | + dev_err(dev, "failed to create device link"); | |
| 463 | + ret = -EINVAL; | |
| 464 | + goto err_devlink; | |
| 465 | + } | |
| 466 | + | |
| 459 | 467 | /* Attach the panel-bridge to the dsi bridge */ |
| 460 | − return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, | |
| 461 | − &ps_bridge->bridge, flags); | |
| 468 | + ret = drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, | |
| 469 | + &ps_bridge->bridge, flags); | |
| 470 | + if (ret) | |
| 471 | + goto err_bridge_attach; | |
| 472 | + | |
| 473 | + return 0; | |
| 474 | + | |
| 475 | +err_bridge_attach: | |
| 476 | + device_link_del(ps_bridge->link); | |
| 477 | +err_devlink: | |
| 478 | + drm_dp_aux_unregister(&ps_bridge->aux); | |
| 479 | + | |
| 480 | + return ret; | |
| 462 | 481 | } |
| 463 | 482 | |
| 464 | 483 | static void ps8640_bridge_detach(struct drm_bridge *bridge) |
| 465 | 484 | { |
| 466 | − drm_dp_aux_unregister(&bridge_to_ps8640(bridge)->aux); | |
| 485 | + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); | |
| 486 | + | |
| 487 | + drm_dp_aux_unregister(&ps_bridge->aux); | |
| 488 | + if (ps_bridge->link) | |
| 489 | + device_link_del(ps_bridge->link); | |
| 467 | 490 | } |
| 468 | 491 | |
| 469 | 492 | static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, |
| @@ -166,10 +166,12 @@ struct sii902x { · 165 unmodified lines | ||
| 166 | 166 | struct i2c_client *i2c; |
| 167 | 167 | struct regmap *regmap; |
| 168 | 168 | struct drm_bridge bridge; |
| 169 | + struct drm_bridge *next_bridge; | |
| 169 | 170 | struct drm_connector connector; |
| 170 | 171 | struct gpio_desc *reset_gpio; |
| 171 | 172 | struct i2c_mux_core *i2cmux; |
| 172 | 173 | struct regulator_bulk_data supplies[2]; |
| 174 | + bool sink_is_hdmi; | |
| 173 | 175 | /* |
| 174 | 176 | * Mutex protects audio and video functions from interfering |
| 175 | 177 | * each other, by keeping their i2c command sequences atomic. |
| @@ -245,10 +247,8 @@ static void sii902x_reset(struct sii902x *sii902x) · 69 unmodified lines | ||
| 245 | 247 | gpiod_set_value(sii902x->reset_gpio, 0); |
| 246 | 248 | } |
| 247 | 249 | |
| 248 | −static enum drm_connector_status | |
| 249 | −sii902x_connector_detect(struct drm_connector *connector, bool force) | |
| 250 | +static enum drm_connector_status sii902x_detect(struct sii902x *sii902x) | |
| 250 | 251 | { |
| 251 | − struct sii902x *sii902x = connector_to_sii902x(connector); | |
| 252 | 252 | unsigned int status; |
| 253 | 253 | |
| 254 | 254 | mutex_lock(&sii902x->mutex); |
| @@ -261,6 +261,14 @@ sii902x_connector_detect(struct drm_connector *connector, bool force) · 6 unmodified lines | ||
| 261 | 261 | connector_status_connected : connector_status_disconnected; |
| 262 | 262 | } |
| 263 | 263 | |
| 264 | +static enum drm_connector_status | |
| 265 | +sii902x_connector_detect(struct drm_connector *connector, bool force) | |
| 266 | +{ | |
| 267 | + struct sii902x *sii902x = connector_to_sii902x(connector); | |
| 268 | + | |
| 269 | + return sii902x_detect(sii902x); | |
| 270 | +} | |
| 271 | + | |
| 264 | 272 | static const struct drm_connector_funcs sii902x_connector_funcs = { |
| 265 | 273 | .detect = sii902x_connector_detect, |
| 266 | 274 | .fill_modes = drm_helper_probe_single_connector_modes, |
| @@ -270,42 +278,40 @@ static const struct drm_connector_funcs sii902x_connector_funcs = { · 3 unmodified lines | ||
| 270 | 278 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 271 | 279 | }; |
| 272 | 280 | |
| 273 | −static int sii902x_get_modes(struct drm_connector *connector) | |
| 281 | +static struct edid *sii902x_get_edid(struct sii902x *sii902x, | |
| 282 | + struct drm_connector *connector) | |
| 274 | 283 | { |
| 275 | − struct sii902x *sii902x = connector_to_sii902x(connector); | |
| 276 | − u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; | |
| 277 | − u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; | |
| 278 | 284 | struct edid *edid; |
| 279 | − int num = 0, ret; | |
| 280 | 285 | |
| 281 | 286 | mutex_lock(&sii902x->mutex); |
| 282 | 287 | |
| 283 | 288 | edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); |
| 284 | − drm_connector_update_edid_property(connector, edid); | |
| 285 | 289 | if (edid) { |
| 286 | 290 | if (drm_detect_hdmi_monitor(edid)) |
| 287 | − output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; | |
| 288 | − | |
| 289 | − num = drm_add_edid_modes(connector, edid); | |
| 290 | − kfree(edid); | |
| 291 | + sii902x->sink_is_hdmi = true; | |
| 292 | + else | |
| 293 | + sii902x->sink_is_hdmi = false; | |
| 291 | 294 | } |
| 292 | 295 | |
| 293 | − ret = drm_display_info_set_bus_formats(&connector->display_info, | |
| 294 | − &bus_format, 1); | |
| 295 | − if (ret) | |
| 296 | − goto error_out; | |
| 296 | + mutex_unlock(&sii902x->mutex); | |
| 297 | 297 | |
| 298 | − ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, | |
| 299 | − SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); | |
| 300 | − if (ret) | |
| 301 | − goto error_out; | |
| 298 | + return edid; | |
| 299 | +} | |
| 302 | 300 | |
| 303 | − ret = num; | |
| 301 | +static int sii902x_get_modes(struct drm_connector *connector) | |
| 302 | +{ | |
| 303 | + struct sii902x *sii902x = connector_to_sii902x(connector); | |
| 304 | + struct edid *edid; | |
| 305 | + int num = 0; | |
| 304 | 306 | |
| 305 | −error_out: | |
| 306 | − mutex_unlock(&sii902x->mutex); | |
| 307 | + edid = sii902x_get_edid(sii902x, connector); | |
| 308 | + drm_connector_update_edid_property(connector, edid); | |
| 309 | + if (edid) { | |
| 310 | + num = drm_add_edid_modes(connector, edid); | |
| 311 | + kfree(edid); | |
| 312 | + } | |
| 307 | 313 | |
| 308 | − return ret; | |
| 314 | + return num; | |
| 309 | 315 | } |
| 310 | 316 | |
| 311 | 317 | 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, · 42 unmodified lines | ||
| 354 | 360 | const struct drm_display_mode *adj) |
| 355 | 361 | { |
| 356 | 362 | struct sii902x *sii902x = bridge_to_sii902x(bridge); |
| 363 | + u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; | |
| 357 | 364 | struct regmap *regmap = sii902x->regmap; |
| 358 | 365 | u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; |
| 359 | 366 | struct hdmi_avi_infoframe frame; |
| 360 | 367 | u16 pixel_clock_10kHz = adj->clock / 10; |
| 361 | 368 | int ret; |
| 362 | 369 | |
| 370 | + if (sii902x->sink_is_hdmi) | |
| 371 | + output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; | |
| 372 | + | |
| 363 | 373 | buf[0] = pixel_clock_10kHz & 0xff; |
| 364 | 374 | buf[1] = pixel_clock_10kHz >> 8; |
| 365 | 375 | buf[2] = drm_mode_vrefresh(adj); |
| @@ -375,6 +385,11 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, · 9 unmodified lines | ||
| 375 | 385 | |
| 376 | 386 | mutex_lock(&sii902x->mutex); |
| 377 | 387 | |
| 388 | + ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, | |
| 389 | + SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); | |
| 390 | + if (ret) | |
| 391 | + goto out; | |
| 392 | + | |
| 378 | 393 | ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10); |
| 379 | 394 | if (ret) |
| 380 | 395 | goto out; |
| @@ -405,13 +420,13 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge, · 24 unmodified lines | ||
| 405 | 420 | enum drm_bridge_attach_flags flags) |
| 406 | 421 | { |
| 407 | 422 | struct sii902x *sii902x = bridge_to_sii902x(bridge); |
| 423 | + u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; | |
| 408 | 424 | struct drm_device *drm = bridge->dev; |
| 409 | 425 | int ret; |
| 410 | 426 | |
| 411 | − if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { | |
| 412 | − DRM_ERROR("Fix bridge driver to make connector optional!"); | |
| 413 | − return -EINVAL; | |
| 414 | − } | |
| 427 | + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) | |
| 428 | + return drm_bridge_attach(bridge->encoder, sii902x->next_bridge, | |
| 429 | + bridge, flags); | |
| 415 | 430 | |
| 416 | 431 | drm_connector_helper_add(&sii902x->connector, |
| 417 | 432 | &sii902x_connector_helper_funcs); |
| @@ -433,16 +448,38 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge, · 15 unmodified lines | ||
| 433 | 448 | else |
| 434 | 449 | sii902x->connector.polled = DRM_CONNECTOR_POLL_CONNECT; |
| 435 | 450 | |
| 451 | + ret = drm_display_info_set_bus_formats(&sii902x->connector.display_info, | |
| 452 | + &bus_format, 1); | |
| 453 | + if (ret) | |
| 454 | + return ret; | |
| 455 | + | |
| 436 | 456 | drm_connector_attach_encoder(&sii902x->connector, bridge->encoder); |
| 437 | 457 | |
| 438 | 458 | return 0; |
| 439 | 459 | } |
| 440 | 460 | |
| 461 | +static enum drm_connector_status sii902x_bridge_detect(struct drm_bridge *bridge) | |
| 462 | +{ | |
| 463 | + struct sii902x *sii902x = bridge_to_sii902x(bridge); | |
| 464 | + | |
| 465 | + return sii902x_detect(sii902x); | |
| 466 | +} | |
| 467 | + | |
| 468 | +static struct edid *sii902x_bridge_get_edid(struct drm_bridge *bridge, | |
| 469 | + struct drm_connector *connector) | |
| 470 | +{ | |
| 471 | + struct sii902x *sii902x = bridge_to_sii902x(bridge); | |
| 472 | + | |
| 473 | + return sii902x_get_edid(sii902x, connector); | |
| 474 | +} | |
| 475 | + | |
| 441 | 476 | static const struct drm_bridge_funcs sii902x_bridge_funcs = { |
| 442 | 477 | .attach = sii902x_bridge_attach, |
| 443 | 478 | .mode_set = sii902x_bridge_mode_set, |
| 444 | 479 | .disable = sii902x_bridge_disable, |
| 445 | 480 | .enable = sii902x_bridge_enable, |
| 481 | + .detect = sii902x_bridge_detect, | |
| 482 | + .get_edid = sii902x_bridge_get_edid, | |
| 446 | 483 | }; |
| 447 | 484 | |
| 448 | 485 | static int sii902x_mute(struct sii902x *sii902x, bool mute) |
| @@ -829,8 +866,12 @@ static irqreturn_t sii902x_interrupt(int irq, void *data) · 380 unmodified lines | ||
| 829 | 866 | |
| 830 | 867 | mutex_unlock(&sii902x->mutex); |
| 831 | 868 | |
| 832 | − if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev) | |
| 869 | + if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev) { | |
| 833 | 870 | drm_helper_hpd_irq_event(sii902x->bridge.dev); |
| 871 | + drm_bridge_hpd_notify(&sii902x->bridge, (status & SII902X_PLUGGED_STATUS) | |
| 872 | + ? connector_status_connected | |
| 873 | + : connector_status_disconnected); | |
| 874 | + } | |
| 834 | 875 | |
| 835 | 876 | return IRQ_HANDLED; |
| 836 | 877 | } |
| @@ -1001,6 +1042,11 @@ static int sii902x_init(struct sii902x *sii902x) · 164 unmodified lines | ||
| 1001 | 1042 | sii902x->bridge.funcs = &sii902x_bridge_funcs; |
| 1002 | 1043 | sii902x->bridge.of_node = dev->of_node; |
| 1003 | 1044 | sii902x->bridge.timings = &default_sii902x_timings; |
| 1045 | + sii902x->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID; | |
| 1046 | + | |
| 1047 | + if (sii902x->i2c->irq > 0) | |
| 1048 | + sii902x->bridge.ops |= DRM_BRIDGE_OP_HPD; | |
| 1049 | + | |
| 1004 | 1050 | drm_bridge_add(&sii902x->bridge); |
| 1005 | 1051 | |
| 1006 | 1052 | sii902x_audio_codec_init(sii902x, dev); |
| @@ -1022,6 +1068,7 @@ static int sii902x_probe(struct i2c_client *client, · 15 unmodified lines | ||
| 1022 | 1068 | const struct i2c_device_id *id) |
| 1023 | 1069 | { |
| 1024 | 1070 | struct device *dev = &client->dev; |
| 1071 | + struct device_node *endpoint; | |
| 1025 | 1072 | struct sii902x *sii902x; |
| 1026 | 1073 | int ret; |
| 1027 | 1074 | |
| @@ -1049,6 +1096,28 @@ static int sii902x_probe(struct i2c_client *client, · 21 unmodified lines | ||
| 1049 | 1096 | return PTR_ERR(sii902x->reset_gpio); |
| 1050 | 1097 | } |
| 1051 | 1098 | |
| 1099 | + endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1); | |
| 1100 | + if (endpoint) { | |
| 1101 | + struct device_node *remote = of_graph_get_remote_port_parent(endpoint); | |
| 1102 | + | |
| 1103 | + of_node_put(endpoint); | |
| 1104 | + if (!remote) { | |
| 1105 | + dev_err(dev, "Endpoint in port@1 unconnected\n"); | |
| 1106 | + return -ENODEV; | |
| 1107 | + } | |
| 1108 | + | |
| 1109 | + if (!of_device_is_available(remote)) { | |
| 1110 | + dev_err(dev, "port@1 remote device is disabled\n"); | |
| 1111 | + of_node_put(remote); | |
| 1112 | + return -ENODEV; | |
| 1113 | + } | |
| 1114 | + | |
| 1115 | + sii902x->next_bridge = of_drm_find_bridge(remote); | |
| 1116 | + of_node_put(remote); | |
| 1117 | + if (!sii902x->next_bridge) | |
| 1118 | + return -EPROBE_DEFER; | |
| 1119 | + } | |
| 1120 | + | |
| 1052 | 1121 | mutex_init(&sii902x->mutex); |
| 1053 | 1122 | |
| 1054 | 1123 | sii902x->supplies[0].supply = "iovcc"; |
| @@ -2120,7 +2120,7 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx) · 2119 unmodified lines | ||
| 2120 | 2120 | if (ret) { |
| 2121 | 2121 | dev_err(ctx->dev, "Failed to register RC device\n"); |
| 2122 | 2122 | ctx->error = ret; |
| 2123 | − rc_free_device(ctx->rc_dev); | |
| 2123 | + rc_free_device(rc_dev); | |
| 2124 | 2124 | return; |
| 2125 | 2125 | } |
| 2126 | 2126 | ctx->rc_dev = rc_dev; |
| @@ -2540,7 +2540,7 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, · 2539 unmodified lines | ||
| 2540 | 2540 | struct drm_display_mode *mode = &crtc_state->mode; |
| 2541 | 2541 | u8 max_bpc = conn_state->max_requested_bpc; |
| 2542 | 2542 | bool is_hdmi2_sink = info->hdmi.scdc.supported || |
| 2543 | − (info->color_formats & DRM_COLOR_FORMAT_YCRCB420); | |
| 2543 | + (info->color_formats & DRM_COLOR_FORMAT_YCBCR420); | |
| 2544 | 2544 | u32 *output_fmts; |
| 2545 | 2545 | unsigned int i = 0; |
| 2546 | 2546 | |
| @@ -2594,36 +2594,36 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, · 47 unmodified lines | ||
| 2594 | 2594 | */ |
| 2595 | 2595 | |
| 2596 | 2596 | if (max_bpc >= 16 && info->bpc == 16) { |
| 2597 | − if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | |
| 2597 | + if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) | |
| 2598 | 2598 | output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; |
| 2599 | 2599 | |
| 2600 | 2600 | output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; |
| 2601 | 2601 | } |
| 2602 | 2602 | |
| 2603 | 2603 | if (max_bpc >= 12 && info->bpc >= 12) { |
| 2604 | − if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | |
| 2604 | + if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) | |
| 2605 | 2605 | output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; |
| 2606 | 2606 | |
| 2607 | − if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | |
| 2607 | + if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) | |
| 2608 | 2608 | output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; |
| 2609 | 2609 | |
| 2610 | 2610 | output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; |
| 2611 | 2611 | } |
| 2612 | 2612 | |
| 2613 | 2613 | if (max_bpc >= 10 && info->bpc >= 10) { |
| 2614 | − if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | |
| 2614 | + if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) | |
| 2615 | 2615 | output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; |
| 2616 | 2616 | |
| 2617 | − if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | |
| 2617 | + if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) | |
| 2618 | 2618 | output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; |
| 2619 | 2619 | |
| 2620 | 2620 | output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; |
| 2621 | 2621 | } |
| 2622 | 2622 | |
| 2623 | − if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | |
| 2623 | + if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) | |
| 2624 | 2624 | output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; |
| 2625 | 2625 | |
| 2626 | − if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | |
| 2626 | + if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) | |
| 2627 | 2627 | output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; |
| 2628 | 2628 | |
| 2629 | 2629 | /* Default 8bit RGB fallback */ |
| @@ -871,7 +871,8 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) · 870 unmodified lines | ||
| 871 | 871 | dsi_write(dsi, DSI_INT_MSK1, 0); |
| 872 | 872 | } |
| 873 | 873 | |
| 874 | −static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) | |
| 874 | +static void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge, | |
| 875 | + struct drm_bridge_state *old_bridge_state) | |
| 875 | 876 | { |
| 876 | 877 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
| 877 | 878 | 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, · 100 unmodified lines | ||
| 978 | 979 | dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode); |
| 979 | 980 | } |
| 980 | 981 | |
| 981 | −static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) | |
| 982 | +static void dw_mipi_dsi_bridge_atomic_enable(struct drm_bridge *bridge, | |
| 983 | + struct drm_bridge_state *old_bridge_state) | |
| 982 | 984 | { |
| 983 | 985 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
| 984 | 986 | |
| @@ -998,7 +1000,10 @@ dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, · 13 unmodified lines | ||
| 998 | 1000 | enum drm_mode_status mode_status = MODE_OK; |
| 999 | 1001 | |
| 1000 | 1002 | if (pdata->mode_valid) |
| 1001 | − mode_status = pdata->mode_valid(pdata->priv_data, mode); | |
| 1003 | + mode_status = pdata->mode_valid(pdata->priv_data, mode, | |
| 1004 | + dsi->mode_flags, | |
| 1005 | + dw_mipi_dsi_get_lanes(dsi), | |
| 1006 | + dsi->format); | |
| 1002 | 1007 | |
| 1003 | 1008 | return mode_status; |
| 1004 | 1009 | } |
| @@ -1032,11 +1037,14 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge, · 27 unmodified lines | ||
| 1032 | 1037 | } |
| 1033 | 1038 | |
| 1034 | 1039 | static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = { |
| 1035 | − .mode_set = dw_mipi_dsi_bridge_mode_set, | |
| 1036 | − .enable = dw_mipi_dsi_bridge_enable, | |
| 1037 | − .post_disable = dw_mipi_dsi_bridge_post_disable, | |
| 1038 | − .mode_valid = dw_mipi_dsi_bridge_mode_valid, | |
| 1039 | − .attach = dw_mipi_dsi_bridge_attach, | |
| 1040 | + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, | |
| 1041 | + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, | |
| 1042 | + .atomic_reset = drm_atomic_helper_bridge_reset, | |
| 1043 | + .atomic_enable = dw_mipi_dsi_bridge_atomic_enable, | |
| 1044 | + .atomic_post_disable = dw_mipi_dsi_bridge_post_atomic_disable, | |
| 1045 | + .mode_set = dw_mipi_dsi_bridge_mode_set, | |
| 1046 | + .mode_valid = dw_mipi_dsi_bridge_mode_valid, | |
| 1047 | + .attach = dw_mipi_dsi_bridge_attach, | |
| 1040 | 1048 | }; |
| 1041 | 1049 | |
| 1042 | 1050 | #ifdef CONFIG_DEBUG_FS |
| @@ -1199,6 +1207,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, · 156 unmodified lines | ||
| 1199 | 1207 | ret = mipi_dsi_host_register(&dsi->dsi_host); |
| 1200 | 1208 | if (ret) { |
| 1201 | 1209 | dev_err(dev, "Failed to register MIPI host: %d\n", ret); |
| 1210 | + pm_runtime_disable(dev); | |
| 1202 | 1211 | dw_mipi_dsi_debugfs_remove(dsi); |
| 1203 | 1212 | return ERR_PTR(ret); |
| 1204 | 1213 | } |
| @@ -27,7 +27,7 @@ · 26 unmodified lines | ||
| 27 | 27 | |
| 28 | 28 | #include <drm/drm_atomic_helper.h> |
| 29 | 29 | #include <drm/drm_bridge.h> |
| 30 | −#include <drm/drm_dp_helper.h> | |
| 30 | +#include <drm/dp/drm_dp_helper.h> | |
| 31 | 31 | #include <drm/drm_edid.h> |
| 32 | 32 | #include <drm/drm_of.h> |
| 33 | 33 | #include <drm/drm_panel.h> |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <drm/drm_atomic_helper.h> |
| 23 | 23 | #include <drm/drm_bridge.h> |
| 24 | 24 | #include <drm/drm_crtc_helper.h> |
| 25 | −#include <drm/drm_dp_helper.h> | |
| 25 | +#include <drm/dp/drm_dp_helper.h> | |
| 26 | 26 | #include <drm/drm_mipi_dsi.h> |
| 27 | 27 | #include <drm/drm_of.h> |
| 28 | 28 | #include <drm/drm_panel.h> |
| @@ -241,7 +241,7 @@ static inline u32 TC358775_LVCFG_PCLKDIV(uint32_t val) · 212 unmodified lines | ||
| 241 | 241 | } |
| 242 | 242 | |
| 243 | 243 | #define TC358775_LVCFG_LVDLINK__MASK 0x00000002 |
| 244 | −#define TC358775_LVCFG_LVDLINK__SHIFT 0 | |
| 244 | +#define TC358775_LVCFG_LVDLINK__SHIFT 1 | |
| 245 | 245 | static inline u32 TC358775_LVCFG_LVDLINK(uint32_t val) |
| 246 | 246 | { |
| 247 | 247 | return ((val) << TC358775_LVCFG_LVDLINK__SHIFT) & |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | #include <linux/of_device.h> |
| 34 | 34 | #include <linux/of_graph.h> |
| 35 | 35 | #include <linux/regmap.h> |
| 36 | +#include <linux/regulator/consumer.h> | |
| 36 | 37 | |
| 37 | 38 | #include <drm/drm_atomic_helper.h> |
| 38 | 39 | #include <drm/drm_bridge.h> |
| @@ -143,6 +144,7 @@ struct sn65dsi83 { · 104 unmodified lines | ||
| 143 | 144 | struct mipi_dsi_device *dsi; |
| 144 | 145 | struct drm_bridge *panel_bridge; |
| 145 | 146 | struct gpio_desc *enable_gpio; |
| 147 | + struct regulator *vcc; | |
| 146 | 148 | int dsi_lanes; |
| 147 | 149 | bool lvds_dual_link; |
| 148 | 150 | bool lvds_dual_link_even_odd_swap; |
| @@ -337,6 +339,12 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, · 188 unmodified lines | ||
| 337 | 339 | u16 val; |
| 338 | 340 | int ret; |
| 339 | 341 | |
| 342 | + ret = regulator_enable(ctx->vcc); | |
| 343 | + if (ret) { | |
| 344 | + dev_err(ctx->dev, "Failed to enable vcc: %d\n", ret); | |
| 345 | + return; | |
| 346 | + } | |
| 347 | + | |
| 340 | 348 | /* Deassert reset */ |
| 341 | 349 | gpiod_set_value(ctx->enable_gpio, 1); |
| 342 | 350 | usleep_range(1000, 1100); |
| @@ -486,11 +494,16 @@ static void sn65dsi83_atomic_disable(struct drm_bridge *bridge, · 143 unmodified lines | ||
| 486 | 494 | struct drm_bridge_state *old_bridge_state) |
| 487 | 495 | { |
| 488 | 496 | struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); |
| 497 | + int ret; | |
| 489 | 498 | |
| 490 | 499 | /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ |
| 491 | 500 | gpiod_set_value(ctx->enable_gpio, 0); |
| 492 | 501 | usleep_range(10000, 11000); |
| 493 | 502 | |
| 503 | + ret = regulator_disable(ctx->vcc); | |
| 504 | + if (ret) | |
| 505 | + dev_err(ctx->dev, "Failed to disable vcc: %d\n", ret); | |
| 506 | + | |
| 494 | 507 | regcache_mark_dirty(ctx->regmap); |
| 495 | 508 | } |
| 496 | 509 | |
| @@ -560,10 +573,14 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) · 63 unmodified lines | ||
| 560 | 573 | ctx->host_node = of_graph_get_remote_port_parent(endpoint); |
| 561 | 574 | of_node_put(endpoint); |
| 562 | 575 | |
| 563 | − if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) | |
| 564 | − return -EINVAL; | |
| 565 | − if (!ctx->host_node) | |
| 566 | − return -ENODEV; | |
| 576 | + if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) { | |
| 577 | + ret = -EINVAL; | |
| 578 | + goto err_put_node; | |
| 579 | + } | |
| 580 | + if (!ctx->host_node) { | |
| 581 | + ret = -ENODEV; | |
| 582 | + goto err_put_node; | |
| 583 | + } | |
| 567 | 584 | |
| 568 | 585 | ctx->lvds_dual_link = false; |
| 569 | 586 | ctx->lvds_dual_link_even_odd_swap = false; |
| @@ -590,16 +607,27 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) · 20 unmodified lines | ||
| 590 | 607 | |
| 591 | 608 | ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, &panel_bridge); |
| 592 | 609 | if (ret < 0) |
| 593 | − return ret; | |
| 610 | + goto err_put_node; | |
| 594 | 611 | if (panel) { |
| 595 | 612 | panel_bridge = devm_drm_panel_bridge_add(dev, panel); |
| 596 | − if (IS_ERR(panel_bridge)) | |
| 597 | − return PTR_ERR(panel_bridge); | |
| 613 | + if (IS_ERR(panel_bridge)) { | |
| 614 | + ret = PTR_ERR(panel_bridge); | |
| 615 | + goto err_put_node; | |
| 616 | + } | |
| 598 | 617 | } |
| 599 | 618 | |
| 600 | 619 | ctx->panel_bridge = panel_bridge; |
| 601 | 620 | |
| 621 | + ctx->vcc = devm_regulator_get(dev, "vcc"); | |
| 622 | + if (IS_ERR(ctx->vcc)) | |
| 623 | + return dev_err_probe(dev, PTR_ERR(ctx->vcc), | |
| 624 | + "Failed to get supply 'vcc'\n"); | |
| 625 | + | |
| 602 | 626 | return 0; |
| 627 | + | |
| 628 | +err_put_node: | |
| 629 | + of_node_put(ctx->host_node); | |
| 630 | + return ret; | |
| 603 | 631 | } |
| 604 | 632 | |
| 605 | 633 | static int sn65dsi83_host_attach(struct sn65dsi83 *ctx) |
| @@ -662,7 +690,8 @@ static int sn65dsi83_probe(struct i2c_client *client, · 56 unmodified lines | ||
| 662 | 690 | } |
| 663 | 691 | |
| 664 | 692 | /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ |
| 665 | − ctx->enable_gpio = devm_gpiod_get(ctx->dev, "enable", GPIOD_OUT_LOW); | |
| 693 | + ctx->enable_gpio = devm_gpiod_get_optional(ctx->dev, "enable", | |
| 694 | + GPIOD_OUT_LOW); | |
| 666 | 695 | if (IS_ERR(ctx->enable_gpio)) |
| 667 | 696 | return PTR_ERR(ctx->enable_gpio); |
| 668 | 697 | |
| @@ -673,8 +702,10 @@ static int sn65dsi83_probe(struct i2c_client *client, · 4 unmodified lines | ||
| 673 | 702 | return ret; |
| 674 | 703 | |
| 675 | 704 | ctx->regmap = devm_regmap_init_i2c(client, &sn65dsi83_regmap_config); |
| 676 | − if (IS_ERR(ctx->regmap)) | |
| 677 | − return PTR_ERR(ctx->regmap); | |
| 705 | + if (IS_ERR(ctx->regmap)) { | |
| 706 | + ret = PTR_ERR(ctx->regmap); | |
| 707 | + goto err_put_node; | |
| 708 | + } | |
| 678 | 709 | |
| 679 | 710 | dev_set_drvdata(dev, ctx); |
| 680 | 711 | i2c_set_clientdata(client, ctx); |
| @@ -691,6 +722,8 @@ static int sn65dsi83_probe(struct i2c_client *client, · 10 unmodified lines | ||
| 691 | 722 | |
| 692 | 723 | err_remove_bridge: |
| 693 | 724 | drm_bridge_remove(&ctx->bridge); |
| 725 | +err_put_node: | |
| 726 | + of_node_put(ctx->host_node); | |
| 694 | 727 | return ret; |
| 695 | 728 | } |
| 696 | 729 | |
| @@ -26,8 +26,8 @@ · 25 unmodified lines | ||
| 26 | 26 | #include <drm/drm_atomic.h> |
| 27 | 27 | #include <drm/drm_atomic_helper.h> |
| 28 | 28 | #include <drm/drm_bridge.h> |
| 29 | −#include <drm/drm_dp_aux_bus.h> | |
| 30 | −#include <drm/drm_dp_helper.h> | |
| 29 | +#include <drm/dp/drm_dp_aux_bus.h> | |
| 30 | +#include <drm/dp/drm_dp_helper.h> | |
| 31 | 31 | #include <drm/drm_mipi_dsi.h> |
| 32 | 32 | #include <drm/drm_of.h> |
| 33 | 33 | #include <drm/drm_panel.h> |
| @@ -0,0 +1,9 @@ | ||
| 1 | +# SPDX-License-Identifier: MIT | |
| 2 | + | |
| 3 | +obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o | |
| 4 | + | |
| 5 | +drm_dp_helper-y := drm_dp.o drm_dp_dual_mode_helper.o drm_dp_helper_mod.o drm_dp_mst_topology.o | |
| 6 | +drm_dp_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o | |
| 7 | +drm_dp_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o | |
| 8 | + | |
| 9 | +obj-$(CONFIG_DRM_DP_HELPER) += drm_dp_helper.o | |
| @@ -29,13 +29,13 @@ · 28 unmodified lines | ||
| 29 | 29 | #include <linux/sched.h> |
| 30 | 30 | #include <linux/seq_file.h> |
| 31 | 31 | |
| 32 | −#include <drm/drm_dp_helper.h> | |
| 32 | +#include <drm/dp/drm_dp_helper.h> | |
| 33 | 33 | #include <drm/drm_print.h> |
| 34 | 34 | #include <drm/drm_vblank.h> |
| 35 | −#include <drm/drm_dp_mst_helper.h> | |
| 35 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 36 | 36 | #include <drm/drm_panel.h> |
| 37 | 37 | |
| 38 | −#include "drm_crtc_helper_internal.h" | |
| 38 | +#include "drm_dp_helper_internal.h" | |
| 39 | 39 | |
| 40 | 40 | struct dp_aux_backlight { |
| 41 | 41 | struct backlight_device *base; |
| @@ -19,8 +19,8 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/pm_domain.h> |
| 20 | 20 | #include <linux/pm_runtime.h> |
| 21 | 21 | |
| 22 | −#include <drm/drm_dp_aux_bus.h> | |
| 23 | −#include <drm/drm_dp_helper.h> | |
| 22 | +#include <drm/dp/drm_dp_aux_bus.h> | |
| 23 | +#include <drm/dp/drm_dp_helper.h> | |
| 24 | 24 | |
| 25 | 25 | /** |
| 26 | 26 | * dp_aux_ep_match() - The match function for the dp_aux_bus. |
| @@ -36,11 +36,11 @@ · 35 unmodified lines | ||
| 36 | 36 | #include <linux/uio.h> |
| 37 | 37 | |
| 38 | 38 | #include <drm/drm_crtc.h> |
| 39 | −#include <drm/drm_dp_helper.h> | |
| 40 | −#include <drm/drm_dp_mst_helper.h> | |
| 39 | +#include <drm/dp/drm_dp_helper.h> | |
| 40 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 41 | 41 | #include <drm/drm_print.h> |
| 42 | 42 | |
| 43 | −#include "drm_crtc_helper_internal.h" | |
| 43 | +#include "drm_dp_helper_internal.h" | |
| 44 | 44 | |
| 45 | 45 | struct drm_dp_aux_dev { |
| 46 | 46 | unsigned index; |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | #include <drm/drm_connector.h> |
| 15 | 15 | #include <drm/drm_device.h> |
| 16 | −#include <drm/drm_dp_helper.h> | |
| 16 | +#include <drm/dp/drm_dp_helper.h> | |
| 17 | 17 | |
| 18 | 18 | /* |
| 19 | 19 | * Unfortunately it turns out that we have a chicken-and-egg situation |
| @@ -28,7 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | #include <linux/string.h> |
| 29 | 29 | |
| 30 | 30 | #include <drm/drm_device.h> |
| 31 | −#include <drm/drm_dp_dual_mode_helper.h> | |
| 31 | +#include <drm/dp/drm_dp_dual_mode_helper.h> | |
| 32 | 32 | #include <drm/drm_print.h> |
| 33 | 33 | |
| 34 | 34 | /** |
| @@ -0,0 +1,33 @@ | ||
| 1 | +/* SPDX-License-Identifier: MIT */ | |
| 2 | + | |
| 3 | +#ifndef DRM_DP_HELPER_INTERNAL_H | |
| 4 | +#define DRM_DP_HELPER_INTERNAL_H | |
| 5 | + | |
| 6 | +struct drm_dp_aux; | |
| 7 | + | |
| 8 | +#ifdef CONFIG_DRM_DP_AUX_CHARDEV | |
| 9 | +int drm_dp_aux_dev_init(void); | |
| 10 | +void drm_dp_aux_dev_exit(void); | |
| 11 | +int drm_dp_aux_register_devnode(struct drm_dp_aux *aux); | |
| 12 | +void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux); | |
| 13 | +#else | |
| 14 | +static inline int drm_dp_aux_dev_init(void) | |
| 15 | +{ | |
| 16 | + return 0; | |
| 17 | +} | |
| 18 | + | |
| 19 | +static inline void drm_dp_aux_dev_exit(void) | |
| 20 | +{ | |
| 21 | +} | |
| 22 | + | |
| 23 | +static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) | |
| 24 | +{ | |
| 25 | + return 0; | |
| 26 | +} | |
| 27 | + | |
| 28 | +static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) | |
| 29 | +{ | |
| 30 | +} | |
| 31 | +#endif | |
| 32 | + | |
| 33 | +#endif | |
| @@ -0,0 +1,22 @@ | ||
| 1 | +// SPDX-License-Identifier: MIT | |
| 2 | + | |
| 3 | +#include <linux/module.h> | |
| 4 | + | |
| 5 | +#include "drm_dp_helper_internal.h" | |
| 6 | + | |
| 7 | +MODULE_DESCRIPTION("DRM DisplayPort helper"); | |
| 8 | +MODULE_LICENSE("GPL and additional rights"); | |
| 9 | + | |
| 10 | +static int __init drm_dp_helper_module_init(void) | |
| 11 | +{ | |
| 12 | + return drm_dp_aux_dev_init(); | |
| 13 | +} | |
| 14 | + | |
| 15 | +static void __exit drm_dp_helper_module_exit(void) | |
| 16 | +{ | |
| 17 | + /* Call exit functions from specific dp helpers here */ | |
| 18 | + drm_dp_aux_dev_exit(); | |
| 19 | +} | |
| 20 | + | |
| 21 | +module_init(drm_dp_helper_module_init); | |
| 22 | +module_exit(drm_dp_helper_module_exit); | |
| @@ -38,14 +38,14 @@ · 37 unmodified lines | ||
| 38 | 38 | #include <linux/math64.h> |
| 39 | 39 | #endif |
| 40 | 40 | |
| 41 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 41 | 42 | #include <drm/drm_atomic.h> |
| 42 | 43 | #include <drm/drm_atomic_helper.h> |
| 43 | −#include <drm/drm_dp_mst_helper.h> | |
| 44 | 44 | #include <drm/drm_drv.h> |
| 45 | 45 | #include <drm/drm_print.h> |
| 46 | 46 | #include <drm/drm_probe_helper.h> |
| 47 | 47 | |
| 48 | −#include "drm_crtc_helper_internal.h" | |
| 48 | +#include "drm_dp_helper_internal.h" | |
| 49 | 49 | #include "drm_dp_mst_topology_internal.h" |
| 50 | 50 | |
| 51 | 51 | /** |
| @@ -4196,7 +4196,7 @@ int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handl · 4144 unmodified lines | ||
| 4196 | 4196 | int ret = 0; |
| 4197 | 4197 | int sc; |
| 4198 | 4198 | *handled = false; |
| 4199 | − sc = esi[0] & 0x3f; | |
| 4199 | + sc = DP_GET_SINK_COUNT(esi[0]); | |
| 4200 | 4200 | |
| 4201 | 4201 | if (sc != mgr->sink_count) { |
| 4202 | 4202 | mgr->sink_count = sc; |
| @@ -4811,7 +4811,7 @@ static void drm_dp_mst_dump_mstb(struct seq_file *m, · 608 unmodified lines | ||
| 4811 | 4811 | |
| 4812 | 4812 | seq_printf(m, "%smstb - [%p]: num_ports: %d\n", prefix, mstb, mstb->num_ports); |
| 4813 | 4813 | list_for_each_entry(port, &mstb->ports, next) { |
| 4814 | − seq_printf(m, "%sport %d - [%p] (%s - %s): ddps: %d, ldps: %d, sdp: %d/%d, fec: %s, conn: %p\n", | |
| 4814 | + seq_printf(m, "%sport %d - [%p] (%s - %s): ddps: %d, ldps: %d, sdp: %d/%d, fec: %s, conn: %p\n", | |
| 4815 | 4815 | prefix, |
| 4816 | 4816 | port->port_num, |
| 4817 | 4817 | port, |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #ifndef _DRM_DP_MST_HELPER_INTERNAL_H_ |
| 11 | 11 | #define _DRM_DP_MST_HELPER_INTERNAL_H_ |
| 12 | 12 | |
| 13 | −#include <drm/drm_dp_mst_helper.h> | |
| 13 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 14 | 14 | |
| 15 | 15 | void |
| 16 | 16 | drm_dp_encode_sideband_req(const struct drm_dp_sideband_msg_req_body *req, |
| @@ -0,0 +1,535 @@ | ||
| 1 | +// SPDX-License-Identifier: MIT | |
| 2 | +/* | |
| 3 | + * Copyright © 2021 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#include <linux/kmemleak.h> | |
| 7 | +#include <linux/module.h> | |
| 8 | +#include <linux/sizes.h> | |
| 9 | + | |
| 10 | +#include <drm/drm_buddy.h> | |
| 11 | + | |
| 12 | +static struct kmem_cache *slab_blocks; | |
| 13 | + | |
| 14 | +static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm, | |
| 15 | + struct drm_buddy_block *parent, | |
| 16 | + unsigned int order, | |
| 17 | + u64 offset) | |
| 18 | +{ | |
| 19 | + struct drm_buddy_block *block; | |
| 20 | + | |
| 21 | + BUG_ON(order > DRM_BUDDY_MAX_ORDER); | |
| 22 | + | |
| 23 | + block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL); | |
| 24 | + if (!block) | |
| 25 | + return NULL; | |
| 26 | + | |
| 27 | + block->header = offset; | |
| 28 | + block->header |= order; | |
| 29 | + block->parent = parent; | |
| 30 | + | |
| 31 | + BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED); | |
| 32 | + return block; | |
| 33 | +} | |
| 34 | + | |
| 35 | +static void drm_block_free(struct drm_buddy *mm, | |
| 36 | + struct drm_buddy_block *block) | |
| 37 | +{ | |
| 38 | + kmem_cache_free(slab_blocks, block); | |
| 39 | +} | |
| 40 | + | |
| 41 | +static void mark_allocated(struct drm_buddy_block *block) | |
| 42 | +{ | |
| 43 | + block->header &= ~DRM_BUDDY_HEADER_STATE; | |
| 44 | + block->header |= DRM_BUDDY_ALLOCATED; | |
| 45 | + | |
| 46 | + list_del(&block->link); | |
| 47 | +} | |
| 48 | + | |
| 49 | +static void mark_free(struct drm_buddy *mm, | |
| 50 | + struct drm_buddy_block *block) | |
| 51 | +{ | |
| 52 | + block->header &= ~DRM_BUDDY_HEADER_STATE; | |
| 53 | + block->header |= DRM_BUDDY_FREE; | |
| 54 | + | |
| 55 | + list_add(&block->link, | |
| 56 | + &mm->free_list[drm_buddy_block_order(block)]); | |
| 57 | +} | |
| 58 | + | |
| 59 | +static void mark_split(struct drm_buddy_block *block) | |
| 60 | +{ | |
| 61 | + block->header &= ~DRM_BUDDY_HEADER_STATE; | |
| 62 | + block->header |= DRM_BUDDY_SPLIT; | |
| 63 | + | |
| 64 | + list_del(&block->link); | |
| 65 | +} | |
| 66 | + | |
| 67 | +/** | |
| 68 | + * drm_buddy_init - init memory manager | |
| 69 | + * | |
| 70 | + * @mm: DRM buddy manager to initialize | |
| 71 | + * @size: size in bytes to manage | |
| 72 | + * @chunk_size: minimum page size in bytes for our allocations | |
| 73 | + * | |
| 74 | + * Initializes the memory manager and its resources. | |
| 75 | + * | |
| 76 | + * Returns: | |
| 77 | + * 0 on success, error code on failure. | |
| 78 | + */ | |
| 79 | +int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) | |
| 80 | +{ | |
| 81 | + unsigned int i; | |
| 82 | + u64 offset; | |
| 83 | + | |
| 84 | + if (size < chunk_size) | |
| 85 | + return -EINVAL; | |
| 86 | + | |
| 87 | + if (chunk_size < PAGE_SIZE) | |
| 88 | + return -EINVAL; | |
| 89 | + | |
| 90 | + if (!is_power_of_2(chunk_size)) | |
| 91 | + return -EINVAL; | |
| 92 | + | |
| 93 | + size = round_down(size, chunk_size); | |
| 94 | + | |
| 95 | + mm->size = size; | |
| 96 | + mm->avail = size; | |
| 97 | + mm->chunk_size = chunk_size; | |
| 98 | + mm->max_order = ilog2(size) - ilog2(chunk_size); | |
| 99 | + | |
| 100 | + BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER); | |
| 101 | + | |
| 102 | + mm->free_list = kmalloc_array(mm->max_order + 1, | |
| 103 | + sizeof(struct list_head), | |
| 104 | + GFP_KERNEL); | |
| 105 | + if (!mm->free_list) | |
| 106 | + return -ENOMEM; | |
| 107 | + | |
| 108 | + for (i = 0; i <= mm->max_order; ++i) | |
| 109 | + INIT_LIST_HEAD(&mm->free_list[i]); | |
| 110 | + | |
| 111 | + mm->n_roots = hweight64(size); | |
| 112 | + | |
| 113 | + mm->roots = kmalloc_array(mm->n_roots, | |
| 114 | + sizeof(struct drm_buddy_block *), | |
| 115 | + GFP_KERNEL); | |
| 116 | + if (!mm->roots) | |
| 117 | + goto out_free_list; | |
| 118 | + | |
| 119 | + offset = 0; | |
| 120 | + i = 0; | |
| 121 | + | |
| 122 | + /* | |
| 123 | + * Split into power-of-two blocks, in case we are given a size that is | |
| 124 | + * not itself a power-of-two. | |
| 125 | + */ | |
| 126 | + do { | |
| 127 | + struct drm_buddy_block *root; | |
| 128 | + unsigned int order; | |
| 129 | + u64 root_size; | |
| 130 | + | |
| 131 | + root_size = rounddown_pow_of_two(size); | |
| 132 | + order = ilog2(root_size) - ilog2(chunk_size); | |
| 133 | + | |
| 134 | + root = drm_block_alloc(mm, NULL, order, offset); | |
| 135 | + if (!root) | |
| 136 | + goto out_free_roots; | |
| 137 | + | |
| 138 | + mark_free(mm, root); | |
| 139 | + | |
| 140 | + BUG_ON(i > mm->max_order); | |
| 141 | + BUG_ON(drm_buddy_block_size(mm, root) < chunk_size); | |
| 142 | + | |
| 143 | + mm->roots[i] = root; | |
| 144 | + | |
| 145 | + offset += root_size; | |
| 146 | + size -= root_size; | |
| 147 | + i++; | |
| 148 | + } while (size); | |
| 149 | + | |
| 150 | + return 0; | |
| 151 | + | |
| 152 | +out_free_roots: | |
| 153 | + while (i--) | |
| 154 | + drm_block_free(mm, mm->roots[i]); | |
| 155 | + kfree(mm->roots); | |
| 156 | +out_free_list: | |
| 157 | + kfree(mm->free_list); | |
| 158 | + return -ENOMEM; | |
| 159 | +} | |
| 160 | +EXPORT_SYMBOL(drm_buddy_init); | |
| 161 | + | |
| 162 | +/** | |
| 163 | + * drm_buddy_fini - tear down the memory manager | |
| 164 | + * | |
| 165 | + * @mm: DRM buddy manager to free | |
| 166 | + * | |
| 167 | + * Cleanup memory manager resources and the freelist | |
| 168 | + */ | |
| 169 | +void drm_buddy_fini(struct drm_buddy *mm) | |
| 170 | +{ | |
| 171 | + int i; | |
| 172 | + | |
| 173 | + for (i = 0; i < mm->n_roots; ++i) { | |
| 174 | + WARN_ON(!drm_buddy_block_is_free(mm->roots[i])); | |
| 175 | + drm_block_free(mm, mm->roots[i]); | |
| 176 | + } | |
| 177 | + | |
| 178 | + WARN_ON(mm->avail != mm->size); | |
| 179 | + | |
| 180 | + kfree(mm->roots); | |
| 181 | + kfree(mm->free_list); | |
| 182 | +} | |
| 183 | +EXPORT_SYMBOL(drm_buddy_fini); | |
| 184 | + | |
| 185 | +static int split_block(struct drm_buddy *mm, | |
| 186 | + struct drm_buddy_block *block) | |
| 187 | +{ | |
| 188 | + unsigned int block_order = drm_buddy_block_order(block) - 1; | |
| 189 | + u64 offset = drm_buddy_block_offset(block); | |
| 190 | + | |
| 191 | + BUG_ON(!drm_buddy_block_is_free(block)); | |
| 192 | + BUG_ON(!drm_buddy_block_order(block)); | |
| 193 | + | |
| 194 | + block->left = drm_block_alloc(mm, block, block_order, offset); | |
| 195 | + if (!block->left) | |
| 196 | + return -ENOMEM; | |
| 197 | + | |
| 198 | + block->right = drm_block_alloc(mm, block, block_order, | |
| 199 | + offset + (mm->chunk_size << block_order)); | |
| 200 | + if (!block->right) { | |
| 201 | + drm_block_free(mm, block->left); | |
| 202 | + return -ENOMEM; | |
| 203 | + } | |
| 204 | + | |
| 205 | + mark_free(mm, block->left); | |
| 206 | + mark_free(mm, block->right); | |
| 207 | + | |
| 208 | + mark_split(block); | |
| 209 | + | |
| 210 | + return 0; | |
| 211 | +} | |
| 212 | + | |
| 213 | +static struct drm_buddy_block * | |
| 214 | +get_buddy(struct drm_buddy_block *block) | |
| 215 | +{ | |
| 216 | + struct drm_buddy_block *parent; | |
| 217 | + | |
| 218 | + parent = block->parent; | |
| 219 | + if (!parent) | |
| 220 | + return NULL; | |
| 221 | + | |
| 222 | + if (parent->left == block) | |
| 223 | + return parent->right; | |
| 224 | + | |
| 225 | + return parent->left; | |
| 226 | +} | |
| 227 | + | |
| 228 | +static void __drm_buddy_free(struct drm_buddy *mm, | |
| 229 | + struct drm_buddy_block *block) | |
| 230 | +{ | |
| 231 | + struct drm_buddy_block *parent; | |
| 232 | + | |
| 233 | + while ((parent = block->parent)) { | |
| 234 | + struct drm_buddy_block *buddy; | |
| 235 | + | |
| 236 | + buddy = get_buddy(block); | |
| 237 | + | |
| 238 | + if (!drm_buddy_block_is_free(buddy)) | |
| 239 | + break; | |
| 240 | + | |
| 241 | + list_del(&buddy->link); | |
| 242 | + | |
| 243 | + drm_block_free(mm, block); | |
| 244 | + drm_block_free(mm, buddy); | |
| 245 | + | |
| 246 | + block = parent; | |
| 247 | + } | |
| 248 | + | |
| 249 | + mark_free(mm, block); | |
| 250 | +} | |
| 251 | + | |
| 252 | +/** | |
| 253 | + * drm_buddy_free_block - free a block | |
| 254 | + * | |
| 255 | + * @mm: DRM buddy manager | |
| 256 | + * @block: block to be freed | |
| 257 | + */ | |
| 258 | +void drm_buddy_free_block(struct drm_buddy *mm, | |
| 259 | + struct drm_buddy_block *block) | |
| 260 | +{ | |
| 261 | + BUG_ON(!drm_buddy_block_is_allocated(block)); | |
| 262 | + mm->avail += drm_buddy_block_size(mm, block); | |
| 263 | + __drm_buddy_free(mm, block); | |
| 264 | +} | |
| 265 | +EXPORT_SYMBOL(drm_buddy_free_block); | |
| 266 | + | |
| 267 | +/** | |
| 268 | + * drm_buddy_free_list - free blocks | |
| 269 | + * | |
| 270 | + * @mm: DRM buddy manager | |
| 271 | + * @objects: input list head to free blocks | |
| 272 | + */ | |
| 273 | +void drm_buddy_free_list(struct drm_buddy *mm, struct list_head *objects) | |
| 274 | +{ | |
| 275 | + struct drm_buddy_block *block, *on; | |
| 276 | + | |
| 277 | + list_for_each_entry_safe(block, on, objects, link) { | |
| 278 | + drm_buddy_free_block(mm, block); | |
| 279 | + cond_resched(); | |
| 280 | + } | |
| 281 | + INIT_LIST_HEAD(objects); | |
| 282 | +} | |
| 283 | +EXPORT_SYMBOL(drm_buddy_free_list); | |
| 284 | + | |
| 285 | +/** | |
| 286 | + * drm_buddy_alloc_blocks - allocate power-of-two blocks | |
| 287 | + * | |
| 288 | + * @mm: DRM buddy manager to allocate from | |
| 289 | + * @order: size of the allocation | |
| 290 | + * | |
| 291 | + * The order value here translates to: | |
| 292 | + * | |
| 293 | + * 0 = 2^0 * mm->chunk_size | |
| 294 | + * 1 = 2^1 * mm->chunk_size | |
| 295 | + * 2 = 2^2 * mm->chunk_size | |
| 296 | + * | |
| 297 | + * Returns: | |
| 298 | + * allocated ptr to the &drm_buddy_block on success | |
| 299 | + */ | |
| 300 | +struct drm_buddy_block * | |
| 301 | +drm_buddy_alloc_blocks(struct drm_buddy *mm, unsigned int order) | |
| 302 | +{ | |
| 303 | + struct drm_buddy_block *block = NULL; | |
| 304 | + unsigned int i; | |
| 305 | + int err; | |
| 306 | + | |
| 307 | + for (i = order; i <= mm->max_order; ++i) { | |
| 308 | + block = list_first_entry_or_null(&mm->free_list[i], | |
| 309 | + struct drm_buddy_block, | |
| 310 | + link); | |
| 311 | + if (block) | |
| 312 | + break; | |
| 313 | + } | |
| 314 | + | |
| 315 | + if (!block) | |
| 316 | + return ERR_PTR(-ENOSPC); | |
| 317 | + | |
| 318 | + BUG_ON(!drm_buddy_block_is_free(block)); | |
| 319 | + | |
| 320 | + while (i != order) { | |
| 321 | + err = split_block(mm, block); | |
| 322 | + if (unlikely(err)) | |
| 323 | + goto out_free; | |
| 324 | + | |
| 325 | + /* Go low */ | |
| 326 | + block = block->left; | |
| 327 | + i--; | |
| 328 | + } | |
| 329 | + | |
| 330 | + mark_allocated(block); | |
| 331 | + mm->avail -= drm_buddy_block_size(mm, block); | |
| 332 | + kmemleak_update_trace(block); | |
| 333 | + return block; | |
| 334 | + | |
| 335 | +out_free: | |
| 336 | + if (i != order) | |
| 337 | + __drm_buddy_free(mm, block); | |
| 338 | + return ERR_PTR(err); | |
| 339 | +} | |
| 340 | +EXPORT_SYMBOL(drm_buddy_alloc_blocks); | |
| 341 | + | |
| 342 | +static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) | |
| 343 | +{ | |
| 344 | + return s1 <= e2 && e1 >= s2; | |
| 345 | +} | |
| 346 | + | |
| 347 | +static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) | |
| 348 | +{ | |
| 349 | + return s1 <= s2 && e1 >= e2; | |
| 350 | +} | |
| 351 | + | |
| 352 | +/** | |
| 353 | + * drm_buddy_alloc_range - allocate range | |
| 354 | + * | |
| 355 | + * @mm: DRM buddy manager to allocate from | |
| 356 | + * @blocks: output list head to add allocated blocks | |
| 357 | + * @start: start of the allowed range for this block | |
| 358 | + * @size: size of the allocation | |
| 359 | + * | |
| 360 | + * Intended for pre-allocating portions of the address space, for example to | |
| 361 | + * reserve a block for the initial framebuffer or similar, hence the expectation | |
| 362 | + * here is that drm_buddy_alloc_blocks() is still the main vehicle for | |
| 363 | + * allocations, so if that's not the case then the drm_mm range allocator is | |
| 364 | + * probably a much better fit, and so you should probably go use that instead. | |
| 365 | + * | |
| 366 | + * Note that it's safe to chain together multiple alloc_ranges | |
| 367 | + * with the same blocks list | |
| 368 | + * | |
| 369 | + * Returns: | |
| 370 | + * 0 on success, error code on failure. | |
| 371 | + */ | |
| 372 | +int drm_buddy_alloc_range(struct drm_buddy *mm, | |
| 373 | + struct list_head *blocks, | |
| 374 | + u64 start, u64 size) | |
| 375 | +{ | |
| 376 | + struct drm_buddy_block *block; | |
| 377 | + struct drm_buddy_block *buddy; | |
| 378 | + LIST_HEAD(allocated); | |
| 379 | + LIST_HEAD(dfs); | |
| 380 | + u64 end; | |
| 381 | + int err; | |
| 382 | + int i; | |
| 383 | + | |
| 384 | + if (size < mm->chunk_size) | |
| 385 | + return -EINVAL; | |
| 386 | + | |
| 387 | + if (!IS_ALIGNED(size | start, mm->chunk_size)) | |
| 388 | + return -EINVAL; | |
| 389 | + | |
| 390 | + if (range_overflows(start, size, mm->size)) | |
| 391 | + return -EINVAL; | |
| 392 | + | |
| 393 | + for (i = 0; i < mm->n_roots; ++i) | |
| 394 | + list_add_tail(&mm->roots[i]->tmp_link, &dfs); | |
| 395 | + | |
| 396 | + end = start + size - 1; | |
| 397 | + | |
| 398 | + do { | |
| 399 | + u64 block_start; | |
| 400 | + u64 block_end; | |
| 401 | + | |
| 402 | + block = list_first_entry_or_null(&dfs, | |
| 403 | + struct drm_buddy_block, | |
| 404 | + tmp_link); | |
| 405 | + if (!block) | |
| 406 | + break; | |
| 407 | + | |
| 408 | + list_del(&block->tmp_link); | |
| 409 | + | |
| 410 | + block_start = drm_buddy_block_offset(block); | |
| 411 | + block_end = block_start + drm_buddy_block_size(mm, block) - 1; | |
| 412 | + | |
| 413 | + if (!overlaps(start, end, block_start, block_end)) | |
| 414 | + continue; | |
| 415 | + | |
| 416 | + if (drm_buddy_block_is_allocated(block)) { | |
| 417 | + err = -ENOSPC; | |
| 418 | + goto err_free; | |
| 419 | + } | |
| 420 | + | |
| 421 | + if (contains(start, end, block_start, block_end)) { | |
| 422 | + if (!drm_buddy_block_is_free(block)) { | |
| 423 | + err = -ENOSPC; | |
| 424 | + goto err_free; | |
| 425 | + } | |
| 426 | + | |
| 427 | + mark_allocated(block); | |
| 428 | + mm->avail -= drm_buddy_block_size(mm, block); | |
| 429 | + list_add_tail(&block->link, &allocated); | |
| 430 | + continue; | |
| 431 | + } | |
| 432 | + | |
| 433 | + if (!drm_buddy_block_is_split(block)) { | |
| 434 | + err = split_block(mm, block); | |
| 435 | + if (unlikely(err)) | |
| 436 | + goto err_undo; | |
| 437 | + } | |
| 438 | + | |
| 439 | + list_add(&block->right->tmp_link, &dfs); | |
| 440 | + list_add(&block->left->tmp_link, &dfs); | |
| 441 | + } while (1); | |
| 442 | + | |
| 443 | + list_splice_tail(&allocated, blocks); | |
| 444 | + return 0; | |
| 445 | + | |
| 446 | +err_undo: | |
| 447 | + /* | |
| 448 | + * We really don't want to leave around a bunch of split blocks, since | |
| 449 | + * bigger is better, so make sure we merge everything back before we | |
| 450 | + * free the allocated blocks. | |
| 451 | + */ | |
| 452 | + buddy = get_buddy(block); | |
| 453 | + if (buddy && | |
| 454 | + (drm_buddy_block_is_free(block) && | |
| 455 | + drm_buddy_block_is_free(buddy))) | |
| 456 | + __drm_buddy_free(mm, block); | |
| 457 | + | |
| 458 | +err_free: | |
| 459 | + drm_buddy_free_list(mm, &allocated); | |
| 460 | + return err; | |
| 461 | +} | |
| 462 | +EXPORT_SYMBOL(drm_buddy_alloc_range); | |
| 463 | + | |
| 464 | +/** | |
| 465 | + * drm_buddy_block_print - print block information | |
| 466 | + * | |
| 467 | + * @mm: DRM buddy manager | |
| 468 | + * @block: DRM buddy block | |
| 469 | + * @p: DRM printer to use | |
| 470 | + */ | |
| 471 | +void drm_buddy_block_print(struct drm_buddy *mm, | |
| 472 | + struct drm_buddy_block *block, | |
| 473 | + struct drm_printer *p) | |
| 474 | +{ | |
| 475 | + u64 start = drm_buddy_block_offset(block); | |
| 476 | + u64 size = drm_buddy_block_size(mm, block); | |
| 477 | + | |
| 478 | + drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size); | |
| 479 | +} | |
| 480 | +EXPORT_SYMBOL(drm_buddy_block_print); | |
| 481 | + | |
| 482 | +/** | |
| 483 | + * drm_buddy_print - print allocator state | |
| 484 | + * | |
| 485 | + * @mm: DRM buddy manager | |
| 486 | + * @p: DRM printer to use | |
| 487 | + */ | |
| 488 | +void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) | |
| 489 | +{ | |
| 490 | + int order; | |
| 491 | + | |
| 492 | + drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n", | |
| 493 | + mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20); | |
| 494 | + | |
| 495 | + for (order = mm->max_order; order >= 0; order--) { | |
| 496 | + struct drm_buddy_block *block; | |
| 497 | + u64 count = 0, free; | |
| 498 | + | |
| 499 | + list_for_each_entry(block, &mm->free_list[order], link) { | |
| 500 | + BUG_ON(!drm_buddy_block_is_free(block)); | |
| 501 | + count++; | |
| 502 | + } | |
| 503 | + | |
| 504 | + drm_printf(p, "order-%d ", order); | |
| 505 | + | |
| 506 | + free = count * (mm->chunk_size << order); | |
| 507 | + if (free < SZ_1M) | |
| 508 | + drm_printf(p, "free: %lluKiB", free >> 10); | |
| 509 | + else | |
| 510 | + drm_printf(p, "free: %lluMiB", free >> 20); | |
| 511 | + | |
| 512 | + drm_printf(p, ", pages: %llu\n", count); | |
| 513 | + } | |
| 514 | +} | |
| 515 | +EXPORT_SYMBOL(drm_buddy_print); | |
| 516 | + | |
| 517 | +static void drm_buddy_module_exit(void) | |
| 518 | +{ | |
| 519 | + kmem_cache_destroy(slab_blocks); | |
| 520 | +} | |
| 521 | + | |
| 522 | +static int __init drm_buddy_module_init(void) | |
| 523 | +{ | |
| 524 | + slab_blocks = KMEM_CACHE(drm_buddy_block, 0); | |
| 525 | + if (!slab_blocks) | |
| 526 | + return -ENOMEM; | |
| 527 | + | |
| 528 | + return 0; | |
| 529 | +} | |
| 530 | + | |
| 531 | +module_init(drm_buddy_module_init); | |
| 532 | +module_exit(drm_buddy_module_exit); | |
| 533 | + | |
| 534 | +MODULE_DESCRIPTION("DRM Buddy Allocator"); | |
| 535 | +MODULE_LICENSE("Dual MIT/GPL"); | |
| @@ -82,6 +82,10 @@ · 81 unmodified lines | ||
| 82 | 82 | * driver boot-up state too. Drivers can access this blob through |
| 83 | 83 | * &drm_crtc_state.gamma_lut. |
| 84 | 84 | * |
| 85 | + * Note that for mostly historical reasons stemming from Xorg heritage, | |
| 86 | + * this is also used to store the color map (also sometimes color lut, CLUT | |
| 87 | + * or color palette) for indexed formats like DRM_FORMAT_C8. | |
| 88 | + * | |
| 85 | 89 | * “GAMMA_LUT_SIZE”: |
| 86 | 90 | * Unsigned range property to give the size of the lookup table to be set |
| 87 | 91 | * on the GAMMA_LUT property (the size depends on the underlying hardware). |
| @@ -28,36 +28,9 @@ · 27 unmodified lines | ||
| 28 | 28 | |
| 29 | 29 | #include <drm/drm_connector.h> |
| 30 | 30 | #include <drm/drm_crtc.h> |
| 31 | −#include <drm/drm_dp_helper.h> | |
| 32 | 31 | #include <drm/drm_encoder.h> |
| 33 | 32 | #include <drm/drm_modes.h> |
| 34 | 33 | |
| 35 | −/* drm_dp_aux_dev.c */ | |
| 36 | −#ifdef CONFIG_DRM_DP_AUX_CHARDEV | |
| 37 | −int drm_dp_aux_dev_init(void); | |
| 38 | −void drm_dp_aux_dev_exit(void); | |
| 39 | −int drm_dp_aux_register_devnode(struct drm_dp_aux *aux); | |
| 40 | −void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux); | |
| 41 | −#else | |
| 42 | −static inline int drm_dp_aux_dev_init(void) | |
| 43 | −{ | |
| 44 | − return 0; | |
| 45 | −} | |
| 46 | − | |
| 47 | −static inline void drm_dp_aux_dev_exit(void) | |
| 48 | −{ | |
| 49 | −} | |
| 50 | − | |
| 51 | −static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) | |
| 52 | −{ | |
| 53 | − return 0; | |
| 54 | −} | |
| 55 | − | |
| 56 | −static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) | |
| 57 | −{ | |
| 58 | −} | |
| 59 | −#endif | |
| 60 | − | |
| 61 | 34 | /* drm_probe_helper.c */ |
| 62 | 35 | enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc, |
| 63 | 36 | const struct drm_display_mode *mode); |
| @@ -12,7 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <linux/errno.h> |
| 13 | 13 | #include <linux/byteorder/generic.h> |
| 14 | 14 | #include <drm/drm_print.h> |
| 15 | −#include <drm/drm_dp_helper.h> | |
| 15 | +#include <drm/dp/drm_dp_helper.h> | |
| 16 | 16 | #include <drm/drm_dsc.h> |
| 17 | 17 | |
| 18 | 18 | /** |
| @@ -93,6 +93,8 @@ static int oui(u8 first, u8 second, u8 third) · 92 unmodified lines | ||
| 93 | 93 | /* Non desktop display (i.e. HMD) */ |
| 94 | 94 | #define EDID_QUIRK_NON_DESKTOP (1 << 12) |
| 95 | 95 | |
| 96 | +#define MICROSOFT_IEEE_OUI 0xca125c | |
| 97 | + | |
| 96 | 98 | struct detailed_mode_closure { |
| 97 | 99 | struct drm_connector *connector; |
| 98 | 100 | struct edid *edid; |
| @@ -212,9 +214,7 @@ static const struct edid_quirk { · 113 unmodified lines | ||
| 212 | 214 | |
| 213 | 215 | /* Windows Mixed Reality Headsets */ |
| 214 | 216 | EDID_QUIRK('A', 'C', 'R', 0x7fce, EDID_QUIRK_NON_DESKTOP), |
| 215 | − EDID_QUIRK('H', 'P', 'N', 0x3515, EDID_QUIRK_NON_DESKTOP), | |
| 216 | 217 | EDID_QUIRK('L', 'E', 'N', 0x0408, EDID_QUIRK_NON_DESKTOP), |
| 217 | − EDID_QUIRK('L', 'E', 'N', 0xb800, EDID_QUIRK_NON_DESKTOP), | |
| 218 | 218 | EDID_QUIRK('F', 'U', 'J', 0x1970, EDID_QUIRK_NON_DESKTOP), |
| 219 | 219 | EDID_QUIRK('D', 'E', 'L', 0x7fce, EDID_QUIRK_NON_DESKTOP), |
| 220 | 220 | EDID_QUIRK('S', 'E', 'C', 0x144a, EDID_QUIRK_NON_DESKTOP), |
| @@ -3776,7 +3776,7 @@ static int do_y420vdb_modes(struct drm_connector *connector, · 3555 unmodified lines | ||
| 3776 | 3776 | } |
| 3777 | 3777 | |
| 3778 | 3778 | if (modes > 0) |
| 3779 | − info->color_formats |= DRM_COLOR_FORMAT_YCRCB420; | |
| 3779 | + info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; | |
| 3780 | 3780 | return modes; |
| 3781 | 3781 | } |
| 3782 | 3782 | |
| @@ -4222,6 +4222,17 @@ static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) · 439 unmodified lines | ||
| 4222 | 4222 | return oui(db[3], db[2], db[1]) == HDMI_FORUM_IEEE_OUI; |
| 4223 | 4223 | } |
| 4224 | 4224 | |
| 4225 | +static bool cea_db_is_microsoft_vsdb(const u8 *db) | |
| 4226 | +{ | |
| 4227 | + if (cea_db_tag(db) != VENDOR_BLOCK) | |
| 4228 | + return false; | |
| 4229 | + | |
| 4230 | + if (cea_db_payload_len(db) != 21) | |
| 4231 | + return false; | |
| 4232 | + | |
| 4233 | + return oui(db[3], db[2], db[1]) == MICROSOFT_IEEE_OUI; | |
| 4234 | +} | |
| 4235 | + | |
| 4225 | 4236 | static bool cea_db_is_vcdb(const u8 *db) |
| 4226 | 4237 | { |
| 4227 | 4238 | if (cea_db_tag(db) != USE_EXTENDED_TAG) |
| @@ -4279,7 +4290,7 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, · 51 unmodified lines | ||
| 4279 | 4290 | if (map_len == 0) { |
| 4280 | 4291 | /* All CEA modes support ycbcr420 sampling also.*/ |
| 4281 | 4292 | hdmi->y420_cmdb_map = U64_MAX; |
| 4282 | − info->color_formats |= DRM_COLOR_FORMAT_YCRCB420; | |
| 4293 | + info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; | |
| 4283 | 4294 | return; |
| 4284 | 4295 | } |
| 4285 | 4296 | |
| @@ -4302,7 +4313,7 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, · 16 unmodified lines | ||
| 4302 | 4313 | map |= (u64)db[2 + count] << (8 * count); |
| 4303 | 4314 | |
| 4304 | 4315 | if (map) |
| 4305 | − info->color_formats |= DRM_COLOR_FORMAT_YCRCB420; | |
| 4316 | + info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; | |
| 4306 | 4317 | |
| 4307 | 4318 | hdmi->y420_cmdb_map = map; |
| 4308 | 4319 | } |
| @@ -5075,21 +5086,21 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, · 766 unmodified lines | ||
| 5075 | 5086 | |
| 5076 | 5087 | if (hdmi[6] & DRM_EDID_HDMI_DC_30) { |
| 5077 | 5088 | dc_bpc = 10; |
| 5078 | − info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30; | |
| 5089 | + info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_30; | |
| 5079 | 5090 | DRM_DEBUG("%s: HDMI sink does deep color 30.\n", |
| 5080 | 5091 | connector->name); |
| 5081 | 5092 | } |
| 5082 | 5093 | |
| 5083 | 5094 | if (hdmi[6] & DRM_EDID_HDMI_DC_36) { |
| 5084 | 5095 | dc_bpc = 12; |
| 5085 | − info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36; | |
| 5096 | + info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_36; | |
| 5086 | 5097 | DRM_DEBUG("%s: HDMI sink does deep color 36.\n", |
| 5087 | 5098 | connector->name); |
| 5088 | 5099 | } |
| 5089 | 5100 | |
| 5090 | 5101 | if (hdmi[6] & DRM_EDID_HDMI_DC_48) { |
| 5091 | 5102 | dc_bpc = 16; |
| 5092 | − info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48; | |
| 5103 | + info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_48; | |
| 5093 | 5104 | DRM_DEBUG("%s: HDMI sink does deep color 48.\n", |
| 5094 | 5105 | connector->name); |
| 5095 | 5106 | } |
| @@ -5104,16 +5115,9 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, · 8 unmodified lines | ||
| 5104 | 5115 | connector->name, dc_bpc); |
| 5105 | 5116 | info->bpc = dc_bpc; |
| 5106 | 5117 | |
| 5107 | − /* | |
| 5108 | − * Deep color support mandates RGB444 support for all video | |
| 5109 | − * modes and forbids YCRCB422 support for all video modes per | |
| 5110 | − * HDMI 1.3 spec. | |
| 5111 | − */ | |
| 5112 | − info->color_formats = DRM_COLOR_FORMAT_RGB444; | |
| 5113 | − | |
| 5114 | 5118 | /* YCRCB444 is optional according to spec. */ |
| 5115 | 5119 | if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { |
| 5116 | − info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; | |
| 5120 | + info->edid_hdmi_ycbcr444_dc_modes = info->edid_hdmi_rgb444_dc_modes; | |
| 5117 | 5121 | DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", |
| 5118 | 5122 | connector->name); |
| 5119 | 5123 | } |
| @@ -5149,6 +5153,25 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db) · 29 unmodified lines | ||
| 5149 | 5153 | drm_parse_hdmi_deep_color_info(connector, db); |
| 5150 | 5154 | } |
| 5151 | 5155 | |
| 5156 | +/* | |
| 5157 | + * See EDID extension for head-mounted and specialized monitors, specified at: | |
| 5158 | + * https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension | |
| 5159 | + */ | |
| 5160 | +static void drm_parse_microsoft_vsdb(struct drm_connector *connector, | |
| 5161 | + const u8 *db) | |
| 5162 | +{ | |
| 5163 | + struct drm_display_info *info = &connector->display_info; | |
| 5164 | + u8 version = db[4]; | |
| 5165 | + bool desktop_usage = db[5] & BIT(6); | |
| 5166 | + | |
| 5167 | + /* Version 1 and 2 for HMDs, version 3 flags desktop usage explicitly */ | |
| 5168 | + if (version == 1 || version == 2 || (version == 3 && !desktop_usage)) | |
| 5169 | + info->non_desktop = true; | |
| 5170 | + | |
| 5171 | + drm_dbg_kms(connector->dev, "HMD or specialized display VSDB version %u: 0x%02x\n", | |
| 5172 | + version, db[5]); | |
| 5173 | +} | |
| 5174 | + | |
| 5152 | 5175 | static void drm_parse_cea_ext(struct drm_connector *connector, |
| 5153 | 5176 | const struct edid *edid) |
| 5154 | 5177 | { |
| @@ -5165,9 +5188,9 @@ static void drm_parse_cea_ext(struct drm_connector *connector, · 10 unmodified lines | ||
| 5165 | 5188 | /* The existence of a CEA block should imply RGB support */ |
| 5166 | 5189 | info->color_formats = DRM_COLOR_FORMAT_RGB444; |
| 5167 | 5190 | if (edid_ext[3] & EDID_CEA_YCRCB444) |
| 5168 | − info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; | |
| 5191 | + info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; | |
| 5169 | 5192 | if (edid_ext[3] & EDID_CEA_YCRCB422) |
| 5170 | − info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; | |
| 5193 | + info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; | |
| 5171 | 5194 | |
| 5172 | 5195 | if (cea_db_offsets(edid_ext, &start, &end)) |
| 5173 | 5196 | return; |
| @@ -5179,6 +5202,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, · 5 unmodified lines | ||
| 5179 | 5202 | drm_parse_hdmi_vsdb_video(connector, db); |
| 5180 | 5203 | if (cea_db_is_hdmi_forum_vsdb(db)) |
| 5181 | 5204 | drm_parse_hdmi_forum_vsdb(connector, db); |
| 5205 | + if (cea_db_is_microsoft_vsdb(db)) | |
| 5206 | + drm_parse_microsoft_vsdb(connector, db); | |
| 5182 | 5207 | if (cea_db_is_y420cmdb(db)) |
| 5183 | 5208 | drm_parse_y420cmdb_bitmap(connector, db); |
| 5184 | 5209 | if (cea_db_is_vcdb(db)) |
| @@ -5333,17 +5358,13 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi · 148 unmodified lines | ||
| 5333 | 5358 | info->width_mm = edid->width_cm * 10; |
| 5334 | 5359 | info->height_mm = edid->height_cm * 10; |
| 5335 | 5360 | |
| 5336 | − info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP); | |
| 5337 | − | |
| 5338 | 5361 | drm_get_monitor_range(connector, edid); |
| 5339 | 5362 | |
| 5340 | − DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop); | |
| 5341 | − | |
| 5342 | 5363 | if (edid->revision < 3) |
| 5343 | − return quirks; | |
| 5364 | + goto out; | |
| 5344 | 5365 | |
| 5345 | 5366 | if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) |
| 5346 | − return quirks; | |
| 5367 | + goto out; | |
| 5347 | 5368 | |
| 5348 | 5369 | drm_parse_cea_ext(connector, edid); |
| 5349 | 5370 | |
| @@ -5363,7 +5384,7 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi · 13 unmodified lines | ||
| 5363 | 5384 | |
| 5364 | 5385 | /* Only defined for 1.4 with digital displays */ |
| 5365 | 5386 | if (edid->revision < 4) |
| 5366 | − return quirks; | |
| 5387 | + goto out; | |
| 5367 | 5388 | |
| 5368 | 5389 | switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) { |
| 5369 | 5390 | case DRM_EDID_DIGITAL_DEPTH_6: |
| @@ -5395,17 +5416,25 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi · 25 unmodified lines | ||
| 5395 | 5416 | |
| 5396 | 5417 | info->color_formats |= DRM_COLOR_FORMAT_RGB444; |
| 5397 | 5418 | if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) |
| 5398 | − info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; | |
| 5419 | + info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; | |
| 5399 | 5420 | if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) |
| 5400 | − info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; | |
| 5421 | + info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; | |
| 5401 | 5422 | |
| 5402 | 5423 | drm_update_mso(connector, edid); |
| 5403 | 5424 | |
| 5425 | +out: | |
| 5426 | + if (quirks & EDID_QUIRK_NON_DESKTOP) { | |
| 5427 | + drm_dbg_kms(connector->dev, "Non-desktop display%s\n", | |
| 5428 | + info->non_desktop ? " (redundant quirk)" : ""); | |
| 5429 | + info->non_desktop = true; | |
| 5430 | + } | |
| 5431 | + | |
| 5404 | 5432 | return quirks; |
| 5405 | 5433 | } |
| 5406 | 5434 | |
| 5407 | 5435 | static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev, |
| 5408 | − struct displayid_detailed_timings_1 *timings) | |
| 5436 | + struct displayid_detailed_timings_1 *timings, | |
| 5437 | + bool type_7) | |
| 5409 | 5438 | { |
| 5410 | 5439 | struct drm_display_mode *mode; |
| 5411 | 5440 | unsigned pixel_clock = (timings->pixel_clock[0] | |
| @@ -5426,7 +5455,8 @@ static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *d · 14 unmodified lines | ||
| 5426 | 5455 | if (!mode) |
| 5427 | 5456 | return NULL; |
| 5428 | 5457 | |
| 5429 | − mode->clock = pixel_clock * 10; | |
| 5458 | + /* resolution is kHz for type VII, and 10 kHz for type I */ | |
| 5459 | + mode->clock = type_7 ? pixel_clock : pixel_clock * 10; | |
| 5430 | 5460 | mode->hdisplay = hactive; |
| 5431 | 5461 | mode->hsync_start = mode->hdisplay + hsync; |
| 5432 | 5462 | mode->hsync_end = mode->hsync_start + hsync_width; |
| @@ -5457,6 +5487,7 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector, · 24 unmodified lines | ||
| 5457 | 5487 | int num_timings; |
| 5458 | 5488 | struct drm_display_mode *newmode; |
| 5459 | 5489 | int num_modes = 0; |
| 5490 | + bool type_7 = block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING; | |
| 5460 | 5491 | /* blocks must be multiple of 20 bytes length */ |
| 5461 | 5492 | if (block->num_bytes % 20) |
| 5462 | 5493 | return 0; |
| @@ -5465,7 +5496,7 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector, · 2 unmodified lines | ||
| 5465 | 5496 | for (i = 0; i < num_timings; i++) { |
| 5466 | 5497 | struct displayid_detailed_timings_1 *timings = &det->timings[i]; |
| 5467 | 5498 | |
| 5468 | − newmode = drm_mode_displayid_detailed(connector->dev, timings); | |
| 5499 | + newmode = drm_mode_displayid_detailed(connector->dev, timings, type_7); | |
| 5469 | 5500 | if (!newmode) |
| 5470 | 5501 | continue; |
| 5471 | 5502 | |
| @@ -5484,7 +5515,8 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, · 12 unmodified lines | ||
| 5484 | 5515 | |
| 5485 | 5516 | displayid_iter_edid_begin(edid, &iter); |
| 5486 | 5517 | displayid_iter_for_each(block, &iter) { |
| 5487 | − if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING) | |
| 5518 | + if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING || | |
| 5519 | + block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING) | |
| 5488 | 5520 | num_modes += add_displayid_detailed_1_modes(connector, block); |
| 5489 | 5521 | } |
| 5490 | 5522 | displayid_iter_end(&iter); |
| @@ -5652,7 +5684,7 @@ static bool is_hdmi2_sink(const struct drm_connector *connector) · 161 unmodified lines | ||
| 5652 | 5684 | return true; |
| 5653 | 5685 | |
| 5654 | 5686 | return connector->display_info.hdmi.scdc.supported || |
| 5655 | − connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420; | |
| 5687 | + connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR420; | |
| 5656 | 5688 | } |
| 5657 | 5689 | |
| 5658 | 5690 | static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf) |
| @@ -5891,13 +5923,13 @@ static const u32 hdmi_colorimetry_val[] = { · 232 unmodified lines | ||
| 5891 | 5923 | #undef ACE |
| 5892 | 5924 | |
| 5893 | 5925 | /** |
| 5894 | − * drm_hdmi_avi_infoframe_colorspace() - fill the HDMI AVI infoframe | |
| 5895 | − * colorspace information | |
| 5926 | + * drm_hdmi_avi_infoframe_colorimetry() - fill the HDMI AVI infoframe | |
| 5927 | + * colorimetry information | |
| 5896 | 5928 | * @frame: HDMI AVI infoframe |
| 5897 | 5929 | * @conn_state: connector state |
| 5898 | 5930 | */ |
| 5899 | 5931 | void |
| 5900 | −drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, | |
| 5932 | +drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, | |
| 5901 | 5933 | const struct drm_connector_state *conn_state) |
| 5902 | 5934 | { |
| 5903 | 5935 | u32 colorimetry_val; |
| @@ -5916,7 +5948,7 @@ drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, · 12 unmodified lines | ||
| 5916 | 5948 | frame->extended_colorimetry = (colorimetry_val >> 2) & |
| 5917 | 5949 | EXTENDED_COLORIMETRY_MASK; |
| 5918 | 5950 | } |
| 5919 | −EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorspace); | |
| 5951 | +EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorimetry); | |
| 5920 | 5952 | |
| 5921 | 5953 | /** |
| 5922 | 5954 | * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe |
| @@ -61,17 +61,3 @@ MODULE_PARM_DESC(edid_firmware, · 60 unmodified lines | ||
| 61 | 61 | "DEPRECATED. Use drm.edid_firmware module parameter instead."); |
| 62 | 62 | |
| 63 | 63 | #endif |
| 64 | − | |
| 65 | −static int __init drm_kms_helper_init(void) | |
| 66 | −{ | |
| 67 | − return drm_dp_aux_dev_init(); | |
| 68 | −} | |
| 69 | − | |
| 70 | −static void __exit drm_kms_helper_exit(void) | |
| 71 | −{ | |
| 72 | − /* Call exit functions from specific kms helpers here */ | |
| 73 | − drm_dp_aux_dev_exit(); | |
| 74 | −} | |
| 75 | − | |
| 76 | −module_init(drm_kms_helper_init); | |
| 77 | −module_exit(drm_kms_helper_exit); | |
| @@ -202,17 +202,13 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane · 201 unmodified lines | ||
| 202 | 202 | |
| 203 | 203 | memcpy(formats_ptr(blob_data), plane->format_types, formats_size); |
| 204 | 204 | |
| 205 | − /* If we can't determine support, just bail */ | |
| 206 | − if (!plane->funcs->format_mod_supported) | |
| 207 | − goto done; | |
| 208 | − | |
| 209 | 205 | mod = modifiers_ptr(blob_data); |
| 210 | 206 | for (i = 0; i < plane->modifier_count; i++) { |
| 211 | 207 | for (j = 0; j < plane->format_count; j++) { |
| 212 | − if (plane->funcs->format_mod_supported(plane, | |
| 208 | + if (!plane->funcs->format_mod_supported || | |
| 209 | + plane->funcs->format_mod_supported(plane, | |
| 213 | 210 | plane->format_types[j], |
| 214 | 211 | plane->modifiers[i])) { |
| 215 | − | |
| 216 | 212 | mod->formats |= 1ULL << j; |
| 217 | 213 | } |
| 218 | 214 | } |
| @@ -223,7 +219,6 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane · 4 unmodified lines | ||
| 223 | 219 | mod++; |
| 224 | 220 | } |
| 225 | 221 | |
| 226 | −done: | |
| 227 | 222 | drm_object_attach_property(&plane->base, config->modifiers_property, |
| 228 | 223 | blob->base.id); |
| 229 | 224 | |
| @@ -387,7 +387,8 @@ static void drm_privacy_screen_device_release(struct device *dev) · 386 unmodified lines | ||
| 387 | 387 | * * An ERR_PTR(errno) on failure. |
| 388 | 388 | */ |
| 389 | 389 | struct drm_privacy_screen *drm_privacy_screen_register( |
| 390 | − struct device *parent, const struct drm_privacy_screen_ops *ops) | |
| 390 | + struct device *parent, const struct drm_privacy_screen_ops *ops, | |
| 391 | + void *data) | |
| 391 | 392 | { |
| 392 | 393 | struct drm_privacy_screen *priv; |
| 393 | 394 | int ret; |
| @@ -404,6 +405,7 @@ struct drm_privacy_screen *drm_privacy_screen_register( · 10 unmodified lines | ||
| 404 | 405 | priv->dev.parent = parent; |
| 405 | 406 | priv->dev.release = drm_privacy_screen_device_release; |
| 406 | 407 | dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent)); |
| 408 | + priv->drvdata = data; | |
| 407 | 409 | priv->ops = ops; |
| 408 | 410 | |
| 409 | 411 | priv->ops->get_hw_state(priv); |
| @@ -439,6 +441,7 @@ void drm_privacy_screen_unregister(struct drm_privacy_screen *priv) · 29 unmodified lines | ||
| 439 | 441 | mutex_unlock(&drm_privacy_screen_devs_lock); |
| 440 | 442 | |
| 441 | 443 | mutex_lock(&priv->lock); |
| 444 | + priv->drvdata = NULL; | |
| 442 | 445 | priv->ops = NULL; |
| 443 | 446 | mutex_unlock(&priv->lock); |
| 444 | 447 | |
| @@ -50,6 +50,13 @@ static bool __init detect_thinkpad_privacy_screen(void) · 49 unmodified lines | ||
| 50 | 50 | } |
| 51 | 51 | #endif |
| 52 | 52 | |
| 53 | +#if IS_ENABLED(CONFIG_CHROMEOS_PRIVACY_SCREEN) | |
| 54 | +static bool __init detect_chromeos_privacy_screen(void) | |
| 55 | +{ | |
| 56 | + return acpi_dev_present("GOOG0010", NULL, -1); | |
| 57 | +} | |
| 58 | +#endif | |
| 59 | + | |
| 53 | 60 | static const struct arch_init_data arch_init_data[] __initconst = { |
| 54 | 61 | #if IS_ENABLED(CONFIG_THINKPAD_ACPI) |
| 55 | 62 | { |
| @@ -61,6 +68,16 @@ static const struct arch_init_data arch_init_data[] __initconst = { · 5 unmodified lines | ||
| 61 | 68 | .detect = detect_thinkpad_privacy_screen, |
| 62 | 69 | }, |
| 63 | 70 | #endif |
| 71 | +#if IS_ENABLED(CONFIG_CHROMEOS_PRIVACY_SCREEN) | |
| 72 | + { | |
| 73 | + .lookup = { | |
| 74 | + .dev_id = NULL, | |
| 75 | + .con_id = NULL, | |
| 76 | + .provider = "privacy_screen-GOOG0010:00", | |
| 77 | + }, | |
| 78 | + .detect = detect_chromeos_privacy_screen, | |
| 79 | + }, | |
| 80 | +#endif | |
| 64 | 81 | }; |
| 65 | 82 | |
| 66 | 83 | void __init drm_privacy_screen_lookup_init(void) |
| @@ -189,8 +189,7 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit) · 188 unmodified lines | ||
| 189 | 189 | continue; |
| 190 | 190 | |
| 191 | 191 | if (bo->flags & ETNA_SUBMIT_BO_WRITE) { |
| 192 | − ret = dma_resv_get_fences(robj, NULL, | |
| 193 | − &bo->nr_shared, | |
| 192 | + ret = dma_resv_get_fences(robj, true, &bo->nr_shared, | |
| 194 | 193 | &bo->shared); |
| 195 | 194 | if (ret) |
| 196 | 195 | return ret; |
| @@ -66,6 +66,7 @@ config DRM_EXYNOS_DP · 65 unmodified lines | ||
| 66 | 66 | bool "Exynos specific extensions for Analogix DP driver" |
| 67 | 67 | depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON |
| 68 | 68 | select DRM_ANALOGIX_DP |
| 69 | + select DRM_DP_HELPER | |
| 69 | 70 | default DRM_EXYNOS |
| 70 | 71 | select DRM_PANEL |
| 71 | 72 | help |
| @@ -258,6 +258,7 @@ struct exynos_dsi { · 257 unmodified lines | ||
| 258 | 258 | struct list_head bridge_chain; |
| 259 | 259 | struct drm_bridge *out_bridge; |
| 260 | 260 | struct device *dev; |
| 261 | + struct drm_display_mode mode; | |
| 261 | 262 | |
| 262 | 263 | void __iomem *reg_base; |
| 263 | 264 | struct phy *phy; |
| @@ -881,7 +882,7 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) · 617 unmodified lines | ||
| 881 | 882 | |
| 882 | 883 | static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi) |
| 883 | 884 | { |
| 884 | − struct drm_display_mode *m = &dsi->encoder.crtc->state->adjusted_mode; | |
| 885 | + struct drm_display_mode *m = &dsi->mode; | |
| 885 | 886 | unsigned int num_bits_resol = dsi->driver_data->num_bits_resol; |
| 886 | 887 | u32 reg; |
| 887 | 888 | |
| @@ -1446,6 +1447,15 @@ static void exynos_dsi_disable(struct drm_encoder *encoder) · 558 unmodified lines | ||
| 1446 | 1447 | pm_runtime_put_sync(dsi->dev); |
| 1447 | 1448 | } |
| 1448 | 1449 | |
| 1450 | +static void exynos_dsi_mode_set(struct drm_encoder *encoder, | |
| 1451 | + struct drm_display_mode *mode, | |
| 1452 | + struct drm_display_mode *adjusted_mode) | |
| 1453 | +{ | |
| 1454 | + struct exynos_dsi *dsi = encoder_to_dsi(encoder); | |
| 1455 | + | |
| 1456 | + drm_mode_copy(&dsi->mode, adjusted_mode); | |
| 1457 | +} | |
| 1458 | + | |
| 1449 | 1459 | static enum drm_connector_status |
| 1450 | 1460 | exynos_dsi_detect(struct drm_connector *connector, bool force) |
| 1451 | 1461 | { |
| @@ -1513,6 +1523,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) · 61 unmodified lines | ||
| 1513 | 1523 | static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = { |
| 1514 | 1524 | .enable = exynos_dsi_enable, |
| 1515 | 1525 | .disable = exynos_dsi_disable, |
| 1526 | + .mode_set = exynos_dsi_mode_set, | |
| 1516 | 1527 | }; |
| 1517 | 1528 | |
| 1518 | 1529 | MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); |
| @@ -31,7 +31,7 @@ · 30 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | #include <drm/drm_crtc.h> |
| 33 | 33 | #include <drm/drm_crtc_helper.h> |
| 34 | −#include <drm/drm_dp_helper.h> | |
| 34 | +#include <drm/dp/drm_dp_helper.h> | |
| 35 | 35 | #include <drm/drm_simple_kms_helper.h> |
| 36 | 36 | |
| 37 | 37 | #include "gma_display.h" |
| @@ -82,7 +82,6 @@ i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading) · 44 unmodified lines | ||
| 82 | 82 | { |
| 83 | 83 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
| 84 | 84 | int mode = MODE_I2C_START; |
| 85 | − int ret; | |
| 86 | 85 | |
| 87 | 86 | if (reading) |
| 88 | 87 | mode |= MODE_I2C_READ; |
| @@ -90,8 +89,7 @@ i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading) · 1 unmodified line | ||
| 90 | 89 | mode |= MODE_I2C_WRITE; |
| 91 | 90 | algo_data->address = address; |
| 92 | 91 | algo_data->running = true; |
| 93 | − ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); | |
| 94 | − return ret; | |
| 92 | + return i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); | |
| 95 | 93 | } |
| 96 | 94 | |
| 97 | 95 | /* |
| @@ -122,13 +120,11 @@ static int · 24 unmodified lines | ||
| 122 | 120 | i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte) |
| 123 | 121 | { |
| 124 | 122 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
| 125 | − int ret; | |
| 126 | 123 | |
| 127 | 124 | if (!algo_data->running) |
| 128 | 125 | return -EIO; |
| 129 | 126 | |
| 130 | − ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL); | |
| 131 | − return ret; | |
| 127 | + return i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL); | |
| 132 | 128 | } |
| 133 | 129 | |
| 134 | 130 | /* |
| @@ -139,13 +135,11 @@ static int · 4 unmodified lines | ||
| 139 | 135 | i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret) |
| 140 | 136 | { |
| 141 | 137 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
| 142 | − int ret; | |
| 143 | 138 | |
| 144 | 139 | if (!algo_data->running) |
| 145 | 140 | return -EIO; |
| 146 | 141 | |
| 147 | − ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret); | |
| 148 | − return ret; | |
| 142 | + return i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret); | |
| 149 | 143 | } |
| 150 | 144 | |
| 151 | 145 | static int |
| @@ -335,7 +335,7 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, · 334 unmodified lines | ||
| 335 | 335 | struct psb_gem_object *pobj; |
| 336 | 336 | struct psb_gem_object *cursor_pobj = gma_crtc->cursor_pobj; |
| 337 | 337 | struct drm_gem_object *obj; |
| 338 | − void *tmp_dst, *tmp_src; | |
| 338 | + void *tmp_dst; | |
| 339 | 339 | int ret = 0, i, cursor_pages; |
| 340 | 340 | |
| 341 | 341 | /* If we didn't get a handle then turn the cursor off */ |
| @@ -400,9 +400,7 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, · 58 unmodified lines | ||
| 400 | 400 | /* Copy the cursor to cursor mem */ |
| 401 | 401 | tmp_dst = dev_priv->vram_addr + cursor_pobj->offset; |
| 402 | 402 | for (i = 0; i < cursor_pages; i++) { |
| 403 | − tmp_src = kmap(pobj->pages[i]); | |
| 404 | − memcpy(tmp_dst, tmp_src, PAGE_SIZE); | |
| 405 | − kunmap(pobj->pages[i]); | |
| 403 | + memcpy_from_page(tmp_dst, pobj->pages[i], 0, PAGE_SIZE); | |
| 406 | 404 | tmp_dst += PAGE_SIZE; |
| 407 | 405 | } |
| 408 | 406 | |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | * Eric Anholt <eric@anholt.net> |
| 7 | 7 | */ |
| 8 | 8 | #include <drm/drm.h> |
| 9 | −#include <drm/drm_dp_helper.h> | |
| 9 | +#include <drm/dp/drm_dp_helper.h> | |
| 10 | 10 | |
| 11 | 11 | #include "intel_bios.h" |
| 12 | 12 | #include "psb_drv.h" |
| @@ -184,17 +184,17 @@ struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, · 183 unmodified lines | ||
| 184 | 184 | pd->invalid_pte = 0; |
| 185 | 185 | } |
| 186 | 186 | |
| 187 | − v = kmap(pd->dummy_pt); | |
| 187 | + v = kmap_local_page(pd->dummy_pt); | |
| 188 | 188 | for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) |
| 189 | 189 | v[i] = pd->invalid_pte; |
| 190 | 190 | |
| 191 | − kunmap(pd->dummy_pt); | |
| 191 | + kunmap_local(v); | |
| 192 | 192 | |
| 193 | − v = kmap(pd->p); | |
| 193 | + v = kmap_local_page(pd->p); | |
| 194 | 194 | for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) |
| 195 | 195 | v[i] = pd->invalid_pde; |
| 196 | 196 | |
| 197 | − kunmap(pd->p); | |
| 197 | + kunmap_local(v); | |
| 198 | 198 | |
| 199 | 199 | clear_page(kmap(pd->dummy_page)); |
| 200 | 200 | kunmap(pd->dummy_page); |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <drm/drm_gem_framebuffer_helper.h> |
| 21 | 21 | #include <drm/drm_gem_vram_helper.h> |
| 22 | 22 | #include <drm/drm_managed.h> |
| 23 | +#include <drm/drm_module.h> | |
| 23 | 24 | #include <drm/drm_vblank.h> |
| 24 | 25 | |
| 25 | 26 | #include "hibmc_drm_drv.h" |
| @@ -379,7 +380,7 @@ static struct pci_driver hibmc_pci_driver = { · 353 unmodified lines | ||
| 379 | 380 | .driver.pm = &hibmc_pm_ops, |
| 380 | 381 | }; |
| 381 | 382 | |
| 382 | −module_pci_driver(hibmc_pci_driver); | |
| 383 | +drm_module_pci_driver(hibmc_pci_driver); | |
| 383 | 384 | |
| 384 | 385 | MODULE_DEVICE_TABLE(pci, hibmc_pci_table); |
| 385 | 386 | MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>"); |
| @@ -9,6 +9,7 @@ config DRM_I915 · 8 unmodified lines | ||
| 9 | 9 | # the shmem_readpage() which depends upon tmpfs |
| 10 | 10 | select SHMEM |
| 11 | 11 | select TMPFS |
| 12 | + select DRM_DP_HELPER | |
| 12 | 13 | select DRM_KMS_HELPER |
| 13 | 14 | select DRM_PANEL |
| 14 | 15 | select DRM_MIPI_DSI |
| @@ -27,6 +28,7 @@ config DRM_I915 · 12 unmodified lines | ||
| 27 | 28 | select CEC_CORE if CEC_NOTIFIER |
| 28 | 29 | select VMAP_PFN |
| 29 | 30 | select DRM_TTM |
| 31 | + select DRM_BUDDY | |
| 30 | 32 | help |
| 31 | 33 | Choose this option if you have a system that has "Intel Graphics |
| 32 | 34 | Media Accelerator" or "HD Graphics" integrated graphics, |
| @@ -161,7 +161,6 @@ gem-y += \ · 160 unmodified lines | ||
| 161 | 161 | i915-y += \ |
| 162 | 162 | $(gem-y) \ |
| 163 | 163 | i915_active.o \ |
| 164 | − i915_buddy.o \ | |
| 165 | 164 | i915_cmd_parser.o \ |
| 166 | 165 | i915_deps.o \ |
| 167 | 166 | i915_gem_evict.o \ |
| @@ -25,7 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | * |
| 26 | 26 | */ |
| 27 | 27 | |
| 28 | −#include <drm/drm_dp_helper.h> | |
| 28 | +#include <drm/dp/drm_dp_helper.h> | |
| 29 | 29 | |
| 30 | 30 | #include "display/intel_display.h" |
| 31 | 31 | #include "display/intel_display_types.h" |
| @@ -38,7 +38,7 @@ · 37 unmodified lines | ||
| 38 | 38 | #include <drm/drm_atomic_helper.h> |
| 39 | 39 | #include <drm/drm_atomic_uapi.h> |
| 40 | 40 | #include <drm/drm_damage_helper.h> |
| 41 | −#include <drm/drm_dp_helper.h> | |
| 41 | +#include <drm/dp/drm_dp_helper.h> | |
| 42 | 42 | #include <drm/drm_edid.h> |
| 43 | 43 | #include <drm/drm_fourcc.h> |
| 44 | 44 | #include <drm/drm_plane_helper.h> |
| @@ -32,10 +32,10 @@ · 31 unmodified lines | ||
| 32 | 32 | #include <linux/pwm.h> |
| 33 | 33 | #include <linux/sched/clock.h> |
| 34 | 34 | |
| 35 | +#include <drm/dp/drm_dp_dual_mode_helper.h> | |
| 36 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 35 | 37 | #include <drm/drm_atomic.h> |
| 36 | 38 | #include <drm/drm_crtc.h> |
| 37 | −#include <drm/drm_dp_dual_mode_helper.h> | |
| 38 | −#include <drm/drm_dp_mst_helper.h> | |
| 39 | 39 | #include <drm/drm_dsc.h> |
| 40 | 40 | #include <drm/drm_encoder.h> |
| 41 | 41 | #include <drm/drm_fb_helper.h> |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | #include <drm/drm_atomic_helper.h> |
| 38 | 38 | #include <drm/drm_crtc.h> |
| 39 | −#include <drm/drm_dp_helper.h> | |
| 39 | +#include <drm/dp/drm_dp_helper.h> | |
| 40 | 40 | #include <drm/drm_edid.h> |
| 41 | 41 | #include <drm/drm_probe_helper.h> |
| 42 | 42 | |
| @@ -6,8 +6,8 @@ · 5 unmodified lines | ||
| 6 | 6 | * Sean Paul <seanpaul@chromium.org> |
| 7 | 7 | */ |
| 8 | 8 | |
| 9 | −#include <drm/drm_dp_helper.h> | |
| 10 | −#include <drm/drm_dp_mst_helper.h> | |
| 9 | +#include <drm/dp/drm_dp_helper.h> | |
| 10 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 11 | 11 | #include <drm/drm_hdcp.h> |
| 12 | 12 | #include <drm/drm_print.h> |
| 13 | 13 | |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #ifndef __INTEL_DP_LINK_TRAINING_H__ |
| 7 | 7 | #define __INTEL_DP_LINK_TRAINING_H__ |
| 8 | 8 | |
| 9 | −#include <drm/drm_dp_helper.h> | |
| 9 | +#include <drm/dp/drm_dp_helper.h> | |
| 10 | 10 | |
| 11 | 11 | struct intel_crtc_state; |
| 12 | 12 | struct intel_dp; |
| @@ -730,7 +730,7 @@ intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder, · 729 unmodified lines | ||
| 730 | 730 | else |
| 731 | 731 | frame->colorspace = HDMI_COLORSPACE_RGB; |
| 732 | 732 | |
| 733 | − drm_hdmi_avi_infoframe_colorspace(frame, conn_state); | |
| 733 | + drm_hdmi_avi_infoframe_colorimetry(frame, conn_state); | |
| 734 | 734 | |
| 735 | 735 | /* nonsense combination */ |
| 736 | 736 | drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range && |
| @@ -1912,7 +1912,7 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *connector, · 1175 unmodified lines | ||
| 1912 | 1912 | if (ycbcr420_output) |
| 1913 | 1913 | return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36; |
| 1914 | 1914 | else |
| 1915 | − return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36; | |
| 1915 | + return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36; | |
| 1916 | 1916 | case 10: |
| 1917 | 1917 | if (!has_hdmi_sink) |
| 1918 | 1918 | return false; |
| @@ -1920,7 +1920,7 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *connector, · 1 unmodified line | ||
| 1920 | 1920 | if (ycbcr420_output) |
| 1921 | 1921 | return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30; |
| 1922 | 1922 | else |
| 1923 | − return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30; | |
| 1923 | + return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30; | |
| 1924 | 1924 | case 8: |
| 1925 | 1925 | return true; |
| 1926 | 1926 | default: |
| @@ -24,7 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | */ |
| 25 | 25 | |
| 26 | 26 | #include <drm/drm_atomic_helper.h> |
| 27 | −#include <drm/drm_dp_dual_mode_helper.h> | |
| 27 | +#include <drm/dp/drm_dp_dual_mode_helper.h> | |
| 28 | 28 | #include <drm/drm_edid.h> |
| 29 | 29 | |
| 30 | 30 | #include "intel_de.h" |
| @@ -537,7 +537,7 @@ void lspcon_set_infoframes(struct intel_encoder *encoder, · 506 unmodified lines | ||
| 537 | 537 | frame.avi.colorspace = HDMI_COLORSPACE_RGB; |
| 538 | 538 | |
| 539 | 539 | /* Set the Colorspace as per the HDMI spec */ |
| 540 | − drm_hdmi_avi_infoframe_colorspace(&frame.avi, conn_state); | |
| 540 | + drm_hdmi_avi_infoframe_colorimetry(&frame.avi, conn_state); | |
| 541 | 541 | |
| 542 | 542 | /* nonsense combination */ |
| 543 | 543 | drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range && |
| @@ -1,466 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: MIT | |
| 2 | −/* | |
| 3 | − * Copyright © 2021 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#include <linux/kmemleak.h> | |
| 7 | −#include <linux/sizes.h> | |
| 8 | − | |
| 9 | −#include "i915_buddy.h" | |
| 10 | − | |
| 11 | −#include "i915_gem.h" | |
| 12 | −#include "i915_utils.h" | |
| 13 | − | |
| 14 | −static struct kmem_cache *slab_blocks; | |
| 15 | − | |
| 16 | −static struct i915_buddy_block *i915_block_alloc(struct i915_buddy_mm *mm, | |
| 17 | − struct i915_buddy_block *parent, | |
| 18 | − unsigned int order, | |
| 19 | − u64 offset) | |
| 20 | −{ | |
| 21 | − struct i915_buddy_block *block; | |
| 22 | − | |
| 23 | − GEM_BUG_ON(order > I915_BUDDY_MAX_ORDER); | |
| 24 | − | |
| 25 | − block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL); | |
| 26 | − if (!block) | |
| 27 | − return NULL; | |
| 28 | − | |
| 29 | − block->header = offset; | |
| 30 | − block->header |= order; | |
| 31 | − block->parent = parent; | |
| 32 | − | |
| 33 | − GEM_BUG_ON(block->header & I915_BUDDY_HEADER_UNUSED); | |
| 34 | − return block; | |
| 35 | −} | |
| 36 | − | |
| 37 | −static void i915_block_free(struct i915_buddy_mm *mm, | |
| 38 | − struct i915_buddy_block *block) | |
| 39 | −{ | |
| 40 | − kmem_cache_free(slab_blocks, block); | |
| 41 | −} | |
| 42 | − | |
| 43 | −static void mark_allocated(struct i915_buddy_block *block) | |
| 44 | −{ | |
| 45 | − block->header &= ~I915_BUDDY_HEADER_STATE; | |
| 46 | − block->header |= I915_BUDDY_ALLOCATED; | |
| 47 | − | |
| 48 | − list_del(&block->link); | |
| 49 | −} | |
| 50 | − | |
| 51 | −static void mark_free(struct i915_buddy_mm *mm, | |
| 52 | − struct i915_buddy_block *block) | |
| 53 | −{ | |
| 54 | − block->header &= ~I915_BUDDY_HEADER_STATE; | |
| 55 | − block->header |= I915_BUDDY_FREE; | |
| 56 | − | |
| 57 | − list_add(&block->link, | |
| 58 | − &mm->free_list[i915_buddy_block_order(block)]); | |
| 59 | −} | |
| 60 | − | |
| 61 | −static void mark_split(struct i915_buddy_block *block) | |
| 62 | −{ | |
| 63 | − block->header &= ~I915_BUDDY_HEADER_STATE; | |
| 64 | − block->header |= I915_BUDDY_SPLIT; | |
| 65 | − | |
| 66 | − list_del(&block->link); | |
| 67 | −} | |
| 68 | − | |
| 69 | −int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size) | |
| 70 | −{ | |
| 71 | − unsigned int i; | |
| 72 | − u64 offset; | |
| 73 | − | |
| 74 | − if (size < chunk_size) | |
| 75 | − return -EINVAL; | |
| 76 | − | |
| 77 | − if (chunk_size < PAGE_SIZE) | |
| 78 | − return -EINVAL; | |
| 79 | − | |
| 80 | − if (!is_power_of_2(chunk_size)) | |
| 81 | − return -EINVAL; | |
| 82 | − | |
| 83 | − size = round_down(size, chunk_size); | |
| 84 | − | |
| 85 | − mm->size = size; | |
| 86 | − mm->avail = size; | |
| 87 | − mm->chunk_size = chunk_size; | |
| 88 | − mm->max_order = ilog2(size) - ilog2(chunk_size); | |
| 89 | − | |
| 90 | − GEM_BUG_ON(mm->max_order > I915_BUDDY_MAX_ORDER); | |
| 91 | − | |
| 92 | − mm->free_list = kmalloc_array(mm->max_order + 1, | |
| 93 | − sizeof(struct list_head), | |
| 94 | − GFP_KERNEL); | |
| 95 | − if (!mm->free_list) | |
| 96 | − return -ENOMEM; | |
| 97 | − | |
| 98 | − for (i = 0; i <= mm->max_order; ++i) | |
| 99 | − INIT_LIST_HEAD(&mm->free_list[i]); | |
| 100 | − | |
| 101 | − mm->n_roots = hweight64(size); | |
| 102 | − | |
| 103 | − mm->roots = kmalloc_array(mm->n_roots, | |
| 104 | − sizeof(struct i915_buddy_block *), | |
| 105 | − GFP_KERNEL); | |
| 106 | − if (!mm->roots) | |
| 107 | − goto out_free_list; | |
| 108 | − | |
| 109 | − offset = 0; | |
| 110 | − i = 0; | |
| 111 | − | |
| 112 | − /* | |
| 113 | − * Split into power-of-two blocks, in case we are given a size that is | |
| 114 | − * not itself a power-of-two. | |
| 115 | − */ | |
| 116 | − do { | |
| 117 | − struct i915_buddy_block *root; | |
| 118 | − unsigned int order; | |
| 119 | − u64 root_size; | |
| 120 | − | |
| 121 | − root_size = rounddown_pow_of_two(size); | |
| 122 | − order = ilog2(root_size) - ilog2(chunk_size); | |
| 123 | − | |
| 124 | − root = i915_block_alloc(mm, NULL, order, offset); | |
| 125 | − if (!root) | |
| 126 | − goto out_free_roots; | |
| 127 | − | |
| 128 | − mark_free(mm, root); | |
| 129 | − | |
| 130 | − GEM_BUG_ON(i > mm->max_order); | |
| 131 | − GEM_BUG_ON(i915_buddy_block_size(mm, root) < chunk_size); | |
| 132 | − | |
| 133 | − mm->roots[i] = root; | |
| 134 | − | |
| 135 | − offset += root_size; | |
| 136 | − size -= root_size; | |
| 137 | − i++; | |
| 138 | − } while (size); | |
| 139 | − | |
| 140 | − return 0; | |
| 141 | − | |
| 142 | −out_free_roots: | |
| 143 | − while (i--) | |
| 144 | − i915_block_free(mm, mm->roots[i]); | |
| 145 | − kfree(mm->roots); | |
| 146 | −out_free_list: | |
| 147 | − kfree(mm->free_list); | |
| 148 | − return -ENOMEM; | |
| 149 | −} | |
| 150 | − | |
| 151 | −void i915_buddy_fini(struct i915_buddy_mm *mm) | |
| 152 | −{ | |
| 153 | − int i; | |
| 154 | − | |
| 155 | − for (i = 0; i < mm->n_roots; ++i) { | |
| 156 | − GEM_WARN_ON(!i915_buddy_block_is_free(mm->roots[i])); | |
| 157 | − i915_block_free(mm, mm->roots[i]); | |
| 158 | − } | |
| 159 | − | |
| 160 | − GEM_WARN_ON(mm->avail != mm->size); | |
| 161 | − | |
| 162 | − kfree(mm->roots); | |
| 163 | − kfree(mm->free_list); | |
| 164 | −} | |
| 165 | − | |
| 166 | −static int split_block(struct i915_buddy_mm *mm, | |
| 167 | − struct i915_buddy_block *block) | |
| 168 | −{ | |
| 169 | − unsigned int block_order = i915_buddy_block_order(block) - 1; | |
| 170 | − u64 offset = i915_buddy_block_offset(block); | |
| 171 | − | |
| 172 | − GEM_BUG_ON(!i915_buddy_block_is_free(block)); | |
| 173 | − GEM_BUG_ON(!i915_buddy_block_order(block)); | |
| 174 | − | |
| 175 | − block->left = i915_block_alloc(mm, block, block_order, offset); | |
| 176 | − if (!block->left) | |
| 177 | − return -ENOMEM; | |
| 178 | − | |
| 179 | − block->right = i915_block_alloc(mm, block, block_order, | |
| 180 | − offset + (mm->chunk_size << block_order)); | |
| 181 | − if (!block->right) { | |
| 182 | − i915_block_free(mm, block->left); | |
| 183 | − return -ENOMEM; | |
| 184 | − } | |
| 185 | − | |
| 186 | − mark_free(mm, block->left); | |
| 187 | − mark_free(mm, block->right); | |
| 188 | − | |
| 189 | − mark_split(block); | |
| 190 | − | |
| 191 | − return 0; | |
| 192 | −} | |
| 193 | − | |
| 194 | −static struct i915_buddy_block * | |
| 195 | −get_buddy(struct i915_buddy_block *block) | |
| 196 | −{ | |
| 197 | − struct i915_buddy_block *parent; | |
| 198 | − | |
| 199 | − parent = block->parent; | |
| 200 | − if (!parent) | |
| 201 | − return NULL; | |
| 202 | − | |
| 203 | − if (parent->left == block) | |
| 204 | − return parent->right; | |
| 205 | − | |
| 206 | − return parent->left; | |
| 207 | −} | |
| 208 | − | |
| 209 | −static void __i915_buddy_free(struct i915_buddy_mm *mm, | |
| 210 | − struct i915_buddy_block *block) | |
| 211 | −{ | |
| 212 | − struct i915_buddy_block *parent; | |
| 213 | − | |
| 214 | − while ((parent = block->parent)) { | |
| 215 | − struct i915_buddy_block *buddy; | |
| 216 | − | |
| 217 | − buddy = get_buddy(block); | |
| 218 | − | |
| 219 | − if (!i915_buddy_block_is_free(buddy)) | |
| 220 | − break; | |
| 221 | − | |
| 222 | − list_del(&buddy->link); | |
| 223 | − | |
| 224 | − i915_block_free(mm, block); | |
| 225 | − i915_block_free(mm, buddy); | |
| 226 | − | |
| 227 | − block = parent; | |
| 228 | − } | |
| 229 | − | |
| 230 | − mark_free(mm, block); | |
| 231 | −} | |
| 232 | − | |
| 233 | −void i915_buddy_free(struct i915_buddy_mm *mm, | |
| 234 | − struct i915_buddy_block *block) | |
| 235 | −{ | |
| 236 | − GEM_BUG_ON(!i915_buddy_block_is_allocated(block)); | |
| 237 | − mm->avail += i915_buddy_block_size(mm, block); | |
| 238 | − __i915_buddy_free(mm, block); | |
| 239 | −} | |
| 240 | − | |
| 241 | −void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects) | |
| 242 | −{ | |
| 243 | − struct i915_buddy_block *block, *on; | |
| 244 | − | |
| 245 | − list_for_each_entry_safe(block, on, objects, link) { | |
| 246 | − i915_buddy_free(mm, block); | |
| 247 | − cond_resched(); | |
| 248 | − } | |
| 249 | − INIT_LIST_HEAD(objects); | |
| 250 | −} | |
| 251 | − | |
| 252 | −/* | |
| 253 | − * Allocate power-of-two block. The order value here translates to: | |
| 254 | − * | |
| 255 | − * 0 = 2^0 * mm->chunk_size | |
| 256 | − * 1 = 2^1 * mm->chunk_size | |
| 257 | − * 2 = 2^2 * mm->chunk_size | |
| 258 | − * ... | |
| 259 | − */ | |
| 260 | −struct i915_buddy_block * | |
| 261 | −i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order) | |
| 262 | −{ | |
| 263 | − struct i915_buddy_block *block = NULL; | |
| 264 | − unsigned int i; | |
| 265 | − int err; | |
| 266 | − | |
| 267 | − for (i = order; i <= mm->max_order; ++i) { | |
| 268 | − block = list_first_entry_or_null(&mm->free_list[i], | |
| 269 | − struct i915_buddy_block, | |
| 270 | − link); | |
| 271 | − if (block) | |
| 272 | − break; | |
| 273 | − } | |
| 274 | − | |
| 275 | − if (!block) | |
| 276 | − return ERR_PTR(-ENOSPC); | |
| 277 | − | |
| 278 | − GEM_BUG_ON(!i915_buddy_block_is_free(block)); | |
| 279 | − | |
| 280 | − while (i != order) { | |
| 281 | − err = split_block(mm, block); | |
| 282 | − if (unlikely(err)) | |
| 283 | − goto out_free; | |
| 284 | − | |
| 285 | − /* Go low */ | |
| 286 | − block = block->left; | |
| 287 | − i--; | |
| 288 | − } | |
| 289 | − | |
| 290 | − mark_allocated(block); | |
| 291 | − mm->avail -= i915_buddy_block_size(mm, block); | |
| 292 | − kmemleak_update_trace(block); | |
| 293 | − return block; | |
| 294 | − | |
| 295 | −out_free: | |
| 296 | − if (i != order) | |
| 297 | − __i915_buddy_free(mm, block); | |
| 298 | − return ERR_PTR(err); | |
| 299 | −} | |
| 300 | − | |
| 301 | −static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) | |
| 302 | −{ | |
| 303 | − return s1 <= e2 && e1 >= s2; | |
| 304 | −} | |
| 305 | − | |
| 306 | −static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) | |
| 307 | −{ | |
| 308 | − return s1 <= s2 && e1 >= e2; | |
| 309 | −} | |
| 310 | − | |
| 311 | −/* | |
| 312 | − * Allocate range. Note that it's safe to chain together multiple alloc_ranges | |
| 313 | − * with the same blocks list. | |
| 314 | − * | |
| 315 | − * Intended for pre-allocating portions of the address space, for example to | |
| 316 | − * reserve a block for the initial framebuffer or similar, hence the expectation | |
| 317 | − * here is that i915_buddy_alloc() is still the main vehicle for | |
| 318 | − * allocations, so if that's not the case then the drm_mm range allocator is | |
| 319 | − * probably a much better fit, and so you should probably go use that instead. | |
| 320 | − */ | |
| 321 | −int i915_buddy_alloc_range(struct i915_buddy_mm *mm, | |
| 322 | − struct list_head *blocks, | |
| 323 | − u64 start, u64 size) | |
| 324 | −{ | |
| 325 | − struct i915_buddy_block *block; | |
| 326 | − struct i915_buddy_block *buddy; | |
| 327 | − LIST_HEAD(allocated); | |
| 328 | − LIST_HEAD(dfs); | |
| 329 | − u64 end; | |
| 330 | − int err; | |
| 331 | − int i; | |
| 332 | − | |
| 333 | − if (size < mm->chunk_size) | |
| 334 | − return -EINVAL; | |
| 335 | − | |
| 336 | − if (!IS_ALIGNED(size | start, mm->chunk_size)) | |
| 337 | − return -EINVAL; | |
| 338 | − | |
| 339 | − if (range_overflows(start, size, mm->size)) | |
| 340 | − return -EINVAL; | |
| 341 | − | |
| 342 | − for (i = 0; i < mm->n_roots; ++i) | |
| 343 | − list_add_tail(&mm->roots[i]->tmp_link, &dfs); | |
| 344 | − | |
| 345 | − end = start + size - 1; | |
| 346 | − | |
| 347 | − do { | |
| 348 | − u64 block_start; | |
| 349 | − u64 block_end; | |
| 350 | − | |
| 351 | − block = list_first_entry_or_null(&dfs, | |
| 352 | − struct i915_buddy_block, | |
| 353 | − tmp_link); | |
| 354 | − if (!block) | |
| 355 | − break; | |
| 356 | − | |
| 357 | − list_del(&block->tmp_link); | |
| 358 | − | |
| 359 | − block_start = i915_buddy_block_offset(block); | |
| 360 | − block_end = block_start + i915_buddy_block_size(mm, block) - 1; | |
| 361 | − | |
| 362 | − if (!overlaps(start, end, block_start, block_end)) | |
| 363 | − continue; | |
| 364 | − | |
| 365 | − if (i915_buddy_block_is_allocated(block)) { | |
| 366 | − err = -ENOSPC; | |
| 367 | − goto err_free; | |
| 368 | − } | |
| 369 | − | |
| 370 | − if (contains(start, end, block_start, block_end)) { | |
| 371 | − if (!i915_buddy_block_is_free(block)) { | |
| 372 | − err = -ENOSPC; | |
| 373 | − goto err_free; | |
| 374 | − } | |
| 375 | − | |
| 376 | − mark_allocated(block); | |
| 377 | − mm->avail -= i915_buddy_block_size(mm, block); | |
| 378 | − list_add_tail(&block->link, &allocated); | |
| 379 | − continue; | |
| 380 | − } | |
| 381 | − | |
| 382 | − if (!i915_buddy_block_is_split(block)) { | |
| 383 | − err = split_block(mm, block); | |
| 384 | − if (unlikely(err)) | |
| 385 | − goto err_undo; | |
| 386 | − } | |
| 387 | − | |
| 388 | − list_add(&block->right->tmp_link, &dfs); | |
| 389 | − list_add(&block->left->tmp_link, &dfs); | |
| 390 | − } while (1); | |
| 391 | − | |
| 392 | − list_splice_tail(&allocated, blocks); | |
| 393 | − return 0; | |
| 394 | − | |
| 395 | −err_undo: | |
| 396 | − /* | |
| 397 | − * We really don't want to leave around a bunch of split blocks, since | |
| 398 | − * bigger is better, so make sure we merge everything back before we | |
| 399 | − * free the allocated blocks. | |
| 400 | − */ | |
| 401 | − buddy = get_buddy(block); | |
| 402 | − if (buddy && | |
| 403 | − (i915_buddy_block_is_free(block) && | |
| 404 | − i915_buddy_block_is_free(buddy))) | |
| 405 | − __i915_buddy_free(mm, block); | |
| 406 | − | |
| 407 | −err_free: | |
| 408 | − i915_buddy_free_list(mm, &allocated); | |
| 409 | − return err; | |
| 410 | −} | |
| 411 | − | |
| 412 | −void i915_buddy_block_print(struct i915_buddy_mm *mm, | |
| 413 | − struct i915_buddy_block *block, | |
| 414 | − struct drm_printer *p) | |
| 415 | −{ | |
| 416 | − u64 start = i915_buddy_block_offset(block); | |
| 417 | − u64 size = i915_buddy_block_size(mm, block); | |
| 418 | − | |
| 419 | − drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size); | |
| 420 | −} | |
| 421 | − | |
| 422 | −void i915_buddy_print(struct i915_buddy_mm *mm, struct drm_printer *p) | |
| 423 | −{ | |
| 424 | − int order; | |
| 425 | − | |
| 426 | − drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n", | |
| 427 | − mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20); | |
| 428 | − | |
| 429 | − for (order = mm->max_order; order >= 0; order--) { | |
| 430 | − struct i915_buddy_block *block; | |
| 431 | − u64 count = 0, free; | |
| 432 | − | |
| 433 | − list_for_each_entry(block, &mm->free_list[order], link) { | |
| 434 | − GEM_BUG_ON(!i915_buddy_block_is_free(block)); | |
| 435 | − count++; | |
| 436 | − } | |
| 437 | − | |
| 438 | − drm_printf(p, "order-%d ", order); | |
| 439 | − | |
| 440 | − free = count * (mm->chunk_size << order); | |
| 441 | − if (free < SZ_1M) | |
| 442 | − drm_printf(p, "free: %lluKiB", free >> 10); | |
| 443 | − else | |
| 444 | − drm_printf(p, "free: %lluMiB", free >> 20); | |
| 445 | − | |
| 446 | − drm_printf(p, ", pages: %llu\n", count); | |
| 447 | − } | |
| 448 | −} | |
| 449 | − | |
| 450 | −#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) | |
| 451 | −#include "selftests/i915_buddy.c" | |
| 452 | −#endif | |
| 453 | − | |
| 454 | −void i915_buddy_module_exit(void) | |
| 455 | −{ | |
| 456 | − kmem_cache_destroy(slab_blocks); | |
| 457 | −} | |
| 458 | − | |
| 459 | −int __init i915_buddy_module_init(void) | |
| 460 | −{ | |
| 461 | − slab_blocks = KMEM_CACHE(i915_buddy_block, 0); | |
| 462 | − if (!slab_blocks) | |
| 463 | − return -ENOMEM; | |
| 464 | − | |
| 465 | − return 0; | |
| 466 | −} | |
| @@ -1,143 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: MIT */ | |
| 2 | −/* | |
| 3 | − * Copyright © 2021 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#ifndef __I915_BUDDY_H__ | |
| 7 | −#define __I915_BUDDY_H__ | |
| 8 | − | |
| 9 | −#include <linux/bitops.h> | |
| 10 | −#include <linux/list.h> | |
| 11 | −#include <linux/slab.h> | |
| 12 | − | |
| 13 | −#include <drm/drm_print.h> | |
| 14 | − | |
| 15 | −struct i915_buddy_block { | |
| 16 | −#define I915_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) | |
| 17 | −#define I915_BUDDY_HEADER_STATE GENMASK_ULL(11, 10) | |
| 18 | −#define I915_BUDDY_ALLOCATED (1 << 10) | |
| 19 | −#define I915_BUDDY_FREE (2 << 10) | |
| 20 | −#define I915_BUDDY_SPLIT (3 << 10) | |
| 21 | −/* Free to be used, if needed in the future */ | |
| 22 | −#define I915_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6) | |
| 23 | −#define I915_BUDDY_HEADER_ORDER GENMASK_ULL(5, 0) | |
| 24 | − u64 header; | |
| 25 | − | |
| 26 | − struct i915_buddy_block *left; | |
| 27 | − struct i915_buddy_block *right; | |
| 28 | − struct i915_buddy_block *parent; | |
| 29 | − | |
| 30 | − void *private; /* owned by creator */ | |
| 31 | − | |
| 32 | − /* | |
| 33 | − * While the block is allocated by the user through i915_buddy_alloc*, | |
| 34 | − * the user has ownership of the link, for example to maintain within | |
| 35 | − * a list, if so desired. As soon as the block is freed with | |
| 36 | − * i915_buddy_free* ownership is given back to the mm. | |
| 37 | − */ | |
| 38 | − struct list_head link; | |
| 39 | − struct list_head tmp_link; | |
| 40 | −}; | |
| 41 | − | |
| 42 | −/* Order-zero must be at least PAGE_SIZE */ | |
| 43 | −#define I915_BUDDY_MAX_ORDER (63 - PAGE_SHIFT) | |
| 44 | − | |
| 45 | −/* | |
| 46 | − * Binary Buddy System. | |
| 47 | − * | |
| 48 | − * Locking should be handled by the user, a simple mutex around | |
| 49 | − * i915_buddy_alloc* and i915_buddy_free* should suffice. | |
| 50 | − */ | |
| 51 | −struct i915_buddy_mm { | |
| 52 | − /* Maintain a free list for each order. */ | |
| 53 | − struct list_head *free_list; | |
| 54 | − | |
| 55 | − /* | |
| 56 | − * Maintain explicit binary tree(s) to track the allocation of the | |
| 57 | − * address space. This gives us a simple way of finding a buddy block | |
| 58 | − * and performing the potentially recursive merge step when freeing a | |
| 59 | − * block. Nodes are either allocated or free, in which case they will | |
| 60 | − * also exist on the respective free list. | |
| 61 | − */ | |
| 62 | − struct i915_buddy_block **roots; | |
| 63 | − | |
| 64 | − /* | |
| 65 | − * Anything from here is public, and remains static for the lifetime of | |
| 66 | − * the mm. Everything above is considered do-not-touch. | |
| 67 | − */ | |
| 68 | − unsigned int n_roots; | |
| 69 | − unsigned int max_order; | |
| 70 | − | |
| 71 | − /* Must be at least PAGE_SIZE */ | |
| 72 | − u64 chunk_size; | |
| 73 | − u64 size; | |
| 74 | − u64 avail; | |
| 75 | −}; | |
| 76 | − | |
| 77 | −static inline u64 | |
| 78 | −i915_buddy_block_offset(struct i915_buddy_block *block) | |
| 79 | −{ | |
| 80 | − return block->header & I915_BUDDY_HEADER_OFFSET; | |
| 81 | −} | |
| 82 | − | |
| 83 | −static inline unsigned int | |
| 84 | −i915_buddy_block_order(struct i915_buddy_block *block) | |
| 85 | −{ | |
| 86 | − return block->header & I915_BUDDY_HEADER_ORDER; | |
| 87 | −} | |
| 88 | − | |
| 89 | −static inline unsigned int | |
| 90 | −i915_buddy_block_state(struct i915_buddy_block *block) | |
| 91 | −{ | |
| 92 | − return block->header & I915_BUDDY_HEADER_STATE; | |
| 93 | −} | |
| 94 | − | |
| 95 | −static inline bool | |
| 96 | −i915_buddy_block_is_allocated(struct i915_buddy_block *block) | |
| 97 | −{ | |
| 98 | − return i915_buddy_block_state(block) == I915_BUDDY_ALLOCATED; | |
| 99 | −} | |
| 100 | − | |
| 101 | −static inline bool | |
| 102 | −i915_buddy_block_is_free(struct i915_buddy_block *block) | |
| 103 | −{ | |
| 104 | − return i915_buddy_block_state(block) == I915_BUDDY_FREE; | |
| 105 | −} | |
| 106 | − | |
| 107 | −static inline bool | |
| 108 | −i915_buddy_block_is_split(struct i915_buddy_block *block) | |
| 109 | −{ | |
| 110 | − return i915_buddy_block_state(block) == I915_BUDDY_SPLIT; | |
| 111 | −} | |
| 112 | − | |
| 113 | −static inline u64 | |
| 114 | −i915_buddy_block_size(struct i915_buddy_mm *mm, | |
| 115 | − struct i915_buddy_block *block) | |
| 116 | −{ | |
| 117 | − return mm->chunk_size << i915_buddy_block_order(block); | |
| 118 | −} | |
| 119 | − | |
| 120 | −int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size); | |
| 121 | − | |
| 122 | −void i915_buddy_fini(struct i915_buddy_mm *mm); | |
| 123 | − | |
| 124 | −struct i915_buddy_block * | |
| 125 | −i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order); | |
| 126 | − | |
| 127 | −int i915_buddy_alloc_range(struct i915_buddy_mm *mm, | |
| 128 | − struct list_head *blocks, | |
| 129 | − u64 start, u64 size); | |
| 130 | − | |
| 131 | −void i915_buddy_free(struct i915_buddy_mm *mm, struct i915_buddy_block *block); | |
| 132 | − | |
| 133 | −void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects); | |
| 134 | − | |
| 135 | −void i915_buddy_print(struct i915_buddy_mm *mm, struct drm_printer *p); | |
| 136 | −void i915_buddy_block_print(struct i915_buddy_mm *mm, | |
| 137 | − struct i915_buddy_block *block, | |
| 138 | − struct drm_printer *p); | |
| 139 | − | |
| 140 | −void i915_buddy_module_exit(void); | |
| 141 | −int i915_buddy_module_init(void); | |
| 142 | − | |
| 143 | −#endif | |
| @@ -9,7 +9,6 @@ · 8 unmodified lines | ||
| 9 | 9 | #include "gem/i915_gem_context.h" |
| 10 | 10 | #include "gem/i915_gem_object.h" |
| 11 | 11 | #include "i915_active.h" |
| 12 | −#include "i915_buddy.h" | |
| 13 | 12 | #include "i915_params.h" |
| 14 | 13 | #include "i915_pci.h" |
| 15 | 14 | #include "i915_perf.h" |
| @@ -50,8 +49,6 @@ static const struct { · 34 unmodified lines | ||
| 50 | 49 | { .init = i915_check_nomodeset }, |
| 51 | 50 | { .init = i915_active_module_init, |
| 52 | 51 | .exit = i915_active_module_exit }, |
| 53 | − { .init = i915_buddy_module_init, | |
| 54 | − .exit = i915_buddy_module_exit }, | |
| 55 | 52 | { .init = i915_context_module_init, |
| 56 | 53 | .exit = i915_context_module_exit }, |
| 57 | 54 | { .init = i915_gem_context_module_init, |
| @@ -5,10 +5,9 @@ · 4 unmodified lines | ||
| 5 | 5 | */ |
| 6 | 6 | |
| 7 | 7 | #include "i915_scatterlist.h" |
| 8 | − | |
| 9 | −#include "i915_buddy.h" | |
| 10 | 8 | #include "i915_ttm_buddy_manager.h" |
| 11 | 9 | |
| 10 | +#include <drm/drm_buddy.h> | |
| 12 | 11 | #include <drm/drm_mm.h> |
| 13 | 12 | |
| 14 | 13 | #include <linux/slab.h> |
| @@ -153,9 +152,9 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res, · 138 unmodified lines | ||
| 153 | 152 | struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res); |
| 154 | 153 | const u64 size = res->num_pages << PAGE_SHIFT; |
| 155 | 154 | const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE); |
| 156 | − struct i915_buddy_mm *mm = bman_res->mm; | |
| 155 | + struct drm_buddy *mm = bman_res->mm; | |
| 157 | 156 | struct list_head *blocks = &bman_res->blocks; |
| 158 | − struct i915_buddy_block *block; | |
| 157 | + struct drm_buddy_block *block; | |
| 159 | 158 | struct i915_refct_sgt *rsgt; |
| 160 | 159 | struct scatterlist *sg; |
| 161 | 160 | struct sg_table *st; |
| @@ -181,8 +180,8 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res, · 19 unmodified lines | ||
| 181 | 180 | list_for_each_entry(block, blocks, link) { |
| 182 | 181 | u64 block_size, offset; |
| 183 | 182 | |
| 184 | − block_size = min_t(u64, size, i915_buddy_block_size(mm, block)); | |
| 185 | − offset = i915_buddy_block_offset(block); | |
| 183 | + block_size = min_t(u64, size, drm_buddy_block_size(mm, block)); | |
| 184 | + offset = drm_buddy_block_offset(block); | |
| 186 | 185 | |
| 187 | 186 | while (block_size) { |
| 188 | 187 | u64 len; |
| @@ -8,14 +8,15 @@ · 7 unmodified lines | ||
| 8 | 8 | #include <drm/ttm/ttm_bo_driver.h> |
| 9 | 9 | #include <drm/ttm/ttm_placement.h> |
| 10 | 10 | |
| 11 | +#include <drm/drm_buddy.h> | |
| 12 | + | |
| 11 | 13 | #include "i915_ttm_buddy_manager.h" |
| 12 | 14 | |
| 13 | −#include "i915_buddy.h" | |
| 14 | 15 | #include "i915_gem.h" |
| 15 | 16 | |
| 16 | 17 | struct i915_ttm_buddy_manager { |
| 17 | 18 | struct ttm_resource_manager manager; |
| 18 | − struct i915_buddy_mm mm; | |
| 19 | + struct drm_buddy mm; | |
| 19 | 20 | struct list_head reserved; |
| 20 | 21 | struct mutex lock; |
| 21 | 22 | u64 default_page_size; |
| @@ -34,7 +35,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, · 12 unmodified lines | ||
| 34 | 35 | { |
| 35 | 36 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); |
| 36 | 37 | struct i915_ttm_buddy_resource *bman_res; |
| 37 | − struct i915_buddy_mm *mm = &bman->mm; | |
| 38 | + struct drm_buddy *mm = &bman->mm; | |
| 38 | 39 | unsigned long n_pages; |
| 39 | 40 | unsigned int min_order; |
| 40 | 41 | u64 min_page_size; |
| @@ -73,7 +74,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, · 32 unmodified lines | ||
| 73 | 74 | n_pages = size >> ilog2(mm->chunk_size); |
| 74 | 75 | |
| 75 | 76 | do { |
| 76 | − struct i915_buddy_block *block; | |
| 77 | + struct drm_buddy_block *block; | |
| 77 | 78 | unsigned int order; |
| 78 | 79 | |
| 79 | 80 | order = fls(n_pages) - 1; |
| @@ -82,7 +83,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, · 2 unmodified lines | ||
| 82 | 83 | |
| 83 | 84 | do { |
| 84 | 85 | mutex_lock(&bman->lock); |
| 85 | − block = i915_buddy_alloc(mm, order); | |
| 86 | + block = drm_buddy_alloc_blocks(mm, order); | |
| 86 | 87 | mutex_unlock(&bman->lock); |
| 87 | 88 | if (!IS_ERR(block)) |
| 88 | 89 | break; |
| @@ -106,9 +107,10 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, · 17 unmodified lines | ||
| 106 | 107 | |
| 107 | 108 | err_free_blocks: |
| 108 | 109 | mutex_lock(&bman->lock); |
| 109 | − i915_buddy_free_list(mm, &bman_res->blocks); | |
| 110 | + drm_buddy_free_list(mm, &bman_res->blocks); | |
| 110 | 111 | mutex_unlock(&bman->lock); |
| 111 | 112 | err_free_res: |
| 113 | + ttm_resource_fini(man, &bman_res->base); | |
| 112 | 114 | kfree(bman_res); |
| 113 | 115 | return err; |
| 114 | 116 | } |
| @@ -120,9 +122,10 @@ static void i915_ttm_buddy_man_free(struct ttm_resource_manager *man, · 5 unmodified lines | ||
| 120 | 122 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); |
| 121 | 123 | |
| 122 | 124 | mutex_lock(&bman->lock); |
| 123 | − i915_buddy_free_list(&bman->mm, &bman_res->blocks); | |
| 125 | + drm_buddy_free_list(&bman->mm, &bman_res->blocks); | |
| 124 | 126 | mutex_unlock(&bman->lock); |
| 125 | 127 | |
| 128 | + ttm_resource_fini(man, res); | |
| 126 | 129 | kfree(bman_res); |
| 127 | 130 | } |
| 128 | 131 | |
| @@ -130,17 +133,17 @@ static void i915_ttm_buddy_man_debug(struct ttm_resource_manager *man, · 1 unmodified line | ||
| 130 | 133 | struct drm_printer *printer) |
| 131 | 134 | { |
| 132 | 135 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); |
| 133 | − struct i915_buddy_block *block; | |
| 136 | + struct drm_buddy_block *block; | |
| 134 | 137 | |
| 135 | 138 | mutex_lock(&bman->lock); |
| 136 | 139 | drm_printf(printer, "default_page_size: %lluKiB\n", |
| 137 | 140 | bman->default_page_size >> 10); |
| 138 | 141 | |
| 139 | − i915_buddy_print(&bman->mm, printer); | |
| 142 | + drm_buddy_print(&bman->mm, printer); | |
| 140 | 143 | |
| 141 | 144 | drm_printf(printer, "reserved:\n"); |
| 142 | 145 | list_for_each_entry(block, &bman->reserved, link) |
| 143 | − i915_buddy_block_print(&bman->mm, block, printer); | |
| 146 | + drm_buddy_block_print(&bman->mm, block, printer); | |
| 144 | 147 | mutex_unlock(&bman->lock); |
| 145 | 148 | } |
| 146 | 149 | |
| @@ -190,7 +193,7 @@ int i915_ttm_buddy_man_init(struct ttm_device *bdev, · 43 unmodified lines | ||
| 190 | 193 | if (!bman) |
| 191 | 194 | return -ENOMEM; |
| 192 | 195 | |
| 193 | − err = i915_buddy_init(&bman->mm, size, chunk_size); | |
| 196 | + err = drm_buddy_init(&bman->mm, size, chunk_size); | |
| 194 | 197 | if (err) |
| 195 | 198 | goto err_free_bman; |
| 196 | 199 | |
| @@ -202,7 +205,7 @@ int i915_ttm_buddy_man_init(struct ttm_device *bdev, · 5 unmodified lines | ||
| 202 | 205 | man = &bman->manager; |
| 203 | 206 | man->use_tt = use_tt; |
| 204 | 207 | man->func = &i915_ttm_buddy_manager_func; |
| 205 | − ttm_resource_manager_init(man, bman->mm.size >> PAGE_SHIFT); | |
| 208 | + ttm_resource_manager_init(man, bdev, bman->mm.size >> PAGE_SHIFT); | |
| 206 | 209 | |
| 207 | 210 | ttm_resource_manager_set_used(man, true); |
| 208 | 211 | ttm_set_driver_manager(bdev, type, man); |
| @@ -228,7 +231,7 @@ int i915_ttm_buddy_man_fini(struct ttm_device *bdev, unsigned int type) · 19 unmodified lines | ||
| 228 | 231 | { |
| 229 | 232 | struct ttm_resource_manager *man = ttm_manager_type(bdev, type); |
| 230 | 233 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); |
| 231 | − struct i915_buddy_mm *mm = &bman->mm; | |
| 234 | + struct drm_buddy *mm = &bman->mm; | |
| 232 | 235 | int ret; |
| 233 | 236 | |
| 234 | 237 | ttm_resource_manager_set_used(man, false); |
| @@ -240,8 +243,8 @@ int i915_ttm_buddy_man_fini(struct ttm_device *bdev, unsigned int type) · 5 unmodified lines | ||
| 240 | 243 | ttm_set_driver_manager(bdev, type, NULL); |
| 241 | 244 | |
| 242 | 245 | mutex_lock(&bman->lock); |
| 243 | − i915_buddy_free_list(mm, &bman->reserved); | |
| 244 | − i915_buddy_fini(mm); | |
| 246 | + drm_buddy_free_list(mm, &bman->reserved); | |
| 247 | + drm_buddy_fini(mm); | |
| 245 | 248 | mutex_unlock(&bman->lock); |
| 246 | 249 | |
| 247 | 250 | ttm_resource_manager_cleanup(man); |
| @@ -264,11 +267,11 @@ int i915_ttm_buddy_man_reserve(struct ttm_resource_manager *man, · 16 unmodified lines | ||
| 264 | 267 | u64 start, u64 size) |
| 265 | 268 | { |
| 266 | 269 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); |
| 267 | − struct i915_buddy_mm *mm = &bman->mm; | |
| 270 | + struct drm_buddy *mm = &bman->mm; | |
| 268 | 271 | int ret; |
| 269 | 272 | |
| 270 | 273 | mutex_lock(&bman->lock); |
| 271 | − ret = i915_buddy_alloc_range(mm, &bman->reserved, start, size); | |
| 274 | + ret = drm_buddy_alloc_range(mm, &bman->reserved, start, size); | |
| 272 | 275 | mutex_unlock(&bman->lock); |
| 273 | 276 | |
| 274 | 277 | return ret; |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | struct ttm_device; |
| 15 | 15 | struct ttm_resource_manager; |
| 16 | −struct i915_buddy_mm; | |
| 16 | +struct drm_buddy; | |
| 17 | 17 | |
| 18 | 18 | /** |
| 19 | 19 | * struct i915_ttm_buddy_resource |
| @@ -28,7 +28,7 @@ struct i915_buddy_mm; · 8 unmodified lines | ||
| 28 | 28 | struct i915_ttm_buddy_resource { |
| 29 | 29 | struct ttm_resource base; |
| 30 | 30 | struct list_head blocks; |
| 31 | − struct i915_buddy_mm *mm; | |
| 31 | + struct drm_buddy *mm; | |
| 32 | 32 | }; |
| 33 | 33 | |
| 34 | 34 | /** |
| @@ -1,787 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: MIT | |
| 2 | −/* | |
| 3 | − * Copyright © 2019 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#include <linux/prime_numbers.h> | |
| 7 | − | |
| 8 | −#include "../i915_selftest.h" | |
| 9 | −#include "i915_random.h" | |
| 10 | − | |
| 11 | −static void __igt_dump_block(struct i915_buddy_mm *mm, | |
| 12 | − struct i915_buddy_block *block, | |
| 13 | − bool buddy) | |
| 14 | −{ | |
| 15 | − pr_err("block info: header=%llx, state=%u, order=%d, offset=%llx size=%llx root=%s buddy=%s\n", | |
| 16 | − block->header, | |
| 17 | − i915_buddy_block_state(block), | |
| 18 | − i915_buddy_block_order(block), | |
| 19 | − i915_buddy_block_offset(block), | |
| 20 | − i915_buddy_block_size(mm, block), | |
| 21 | − yesno(!block->parent), | |
| 22 | − yesno(buddy)); | |
| 23 | −} | |
| 24 | − | |
| 25 | −static void igt_dump_block(struct i915_buddy_mm *mm, | |
| 26 | − struct i915_buddy_block *block) | |
| 27 | −{ | |
| 28 | − struct i915_buddy_block *buddy; | |
| 29 | − | |
| 30 | − __igt_dump_block(mm, block, false); | |
| 31 | − | |
| 32 | − buddy = get_buddy(block); | |
| 33 | − if (buddy) | |
| 34 | − __igt_dump_block(mm, buddy, true); | |
| 35 | −} | |
| 36 | − | |
| 37 | −static int igt_check_block(struct i915_buddy_mm *mm, | |
| 38 | − struct i915_buddy_block *block) | |
| 39 | −{ | |
| 40 | − struct i915_buddy_block *buddy; | |
| 41 | − unsigned int block_state; | |
| 42 | − u64 block_size; | |
| 43 | − u64 offset; | |
| 44 | − int err = 0; | |
| 45 | − | |
| 46 | − block_state = i915_buddy_block_state(block); | |
| 47 | − | |
| 48 | − if (block_state != I915_BUDDY_ALLOCATED && | |
| 49 | − block_state != I915_BUDDY_FREE && | |
| 50 | − block_state != I915_BUDDY_SPLIT) { | |
| 51 | − pr_err("block state mismatch\n"); | |
| 52 | − err = -EINVAL; | |
| 53 | − } | |
| 54 | − | |
| 55 | − block_size = i915_buddy_block_size(mm, block); | |
| 56 | − offset = i915_buddy_block_offset(block); | |
| 57 | − | |
| 58 | − if (block_size < mm->chunk_size) { | |
| 59 | − pr_err("block size smaller than min size\n"); | |
| 60 | − err = -EINVAL; | |
| 61 | − } | |
| 62 | − | |
| 63 | − if (!is_power_of_2(block_size)) { | |
| 64 | − pr_err("block size not power of two\n"); | |
| 65 | − err = -EINVAL; | |
| 66 | − } | |
| 67 | − | |
| 68 | − if (!IS_ALIGNED(block_size, mm->chunk_size)) { | |
| 69 | − pr_err("block size not aligned to min size\n"); | |
| 70 | − err = -EINVAL; | |
| 71 | − } | |
| 72 | − | |
| 73 | − if (!IS_ALIGNED(offset, mm->chunk_size)) { | |
| 74 | − pr_err("block offset not aligned to min size\n"); | |
| 75 | − err = -EINVAL; | |
| 76 | − } | |
| 77 | − | |
| 78 | − if (!IS_ALIGNED(offset, block_size)) { | |
| 79 | − pr_err("block offset not aligned to block size\n"); | |
| 80 | − err = -EINVAL; | |
| 81 | − } | |
| 82 | − | |
| 83 | − buddy = get_buddy(block); | |
| 84 | − | |
| 85 | − if (!buddy && block->parent) { | |
| 86 | − pr_err("buddy has gone fishing\n"); | |
| 87 | − err = -EINVAL; | |
| 88 | − } | |
| 89 | − | |
| 90 | − if (buddy) { | |
| 91 | − if (i915_buddy_block_offset(buddy) != (offset ^ block_size)) { | |
| 92 | − pr_err("buddy has wrong offset\n"); | |
| 93 | − err = -EINVAL; | |
| 94 | − } | |
| 95 | − | |
| 96 | − if (i915_buddy_block_size(mm, buddy) != block_size) { | |
| 97 | − pr_err("buddy size mismatch\n"); | |
| 98 | − err = -EINVAL; | |
| 99 | − } | |
| 100 | − | |
| 101 | − if (i915_buddy_block_state(buddy) == block_state && | |
| 102 | − block_state == I915_BUDDY_FREE) { | |
| 103 | − pr_err("block and its buddy are free\n"); | |
| 104 | − err = -EINVAL; | |
| 105 | − } | |
| 106 | − } | |
| 107 | − | |
| 108 | − return err; | |
| 109 | −} | |
| 110 | − | |
| 111 | −static int igt_check_blocks(struct i915_buddy_mm *mm, | |
| 112 | − struct list_head *blocks, | |
| 113 | − u64 expected_size, | |
| 114 | − bool is_contiguous) | |
| 115 | −{ | |
| 116 | − struct i915_buddy_block *block; | |
| 117 | − struct i915_buddy_block *prev; | |
| 118 | − u64 total; | |
| 119 | − int err = 0; | |
| 120 | − | |
| 121 | − block = NULL; | |
| 122 | − prev = NULL; | |
| 123 | − total = 0; | |
| 124 | − | |
| 125 | − list_for_each_entry(block, blocks, link) { | |
| 126 | − err = igt_check_block(mm, block); | |
| 127 | − | |
| 128 | − if (!i915_buddy_block_is_allocated(block)) { | |
| 129 | − pr_err("block not allocated\n"), | |
| 130 | − err = -EINVAL; | |
| 131 | − } | |
| 132 | − | |
| 133 | − if (is_contiguous && prev) { | |
| 134 | − u64 prev_block_size; | |
| 135 | − u64 prev_offset; | |
| 136 | − u64 offset; | |
| 137 | − | |
| 138 | − prev_offset = i915_buddy_block_offset(prev); | |
| 139 | − prev_block_size = i915_buddy_block_size(mm, prev); | |
| 140 | − offset = i915_buddy_block_offset(block); | |
| 141 | − | |
| 142 | − if (offset != (prev_offset + prev_block_size)) { | |
| 143 | − pr_err("block offset mismatch\n"); | |
| 144 | − err = -EINVAL; | |
| 145 | − } | |
| 146 | − } | |
| 147 | − | |
| 148 | − if (err) | |
| 149 | − break; | |
| 150 | − | |
| 151 | − total += i915_buddy_block_size(mm, block); | |
| 152 | − prev = block; | |
| 153 | − } | |
| 154 | − | |
| 155 | − if (!err) { | |
| 156 | − if (total != expected_size) { | |
| 157 | − pr_err("size mismatch, expected=%llx, found=%llx\n", | |
| 158 | − expected_size, total); | |
| 159 | − err = -EINVAL; | |
| 160 | − } | |
| 161 | − return err; | |
| 162 | − } | |
| 163 | − | |
| 164 | − if (prev) { | |
| 165 | − pr_err("prev block, dump:\n"); | |
| 166 | − igt_dump_block(mm, prev); | |
| 167 | − } | |
| 168 | − | |
| 169 | − pr_err("bad block, dump:\n"); | |
| 170 | − igt_dump_block(mm, block); | |
| 171 | − | |
| 172 | − return err; | |
| 173 | −} | |
| 174 | − | |
| 175 | −static int igt_check_mm(struct i915_buddy_mm *mm) | |
| 176 | −{ | |
| 177 | − struct i915_buddy_block *root; | |
| 178 | − struct i915_buddy_block *prev; | |
| 179 | − unsigned int i; | |
| 180 | − u64 total; | |
| 181 | − int err = 0; | |
| 182 | − | |
| 183 | − if (!mm->n_roots) { | |
| 184 | − pr_err("n_roots is zero\n"); | |
| 185 | − return -EINVAL; | |
| 186 | − } | |
| 187 | − | |
| 188 | − if (mm->n_roots != hweight64(mm->size)) { | |
| 189 | − pr_err("n_roots mismatch, n_roots=%u, expected=%lu\n", | |
| 190 | − mm->n_roots, hweight64(mm->size)); | |
| 191 | − return -EINVAL; | |
| 192 | − } | |
| 193 | − | |
| 194 | − root = NULL; | |
| 195 | − prev = NULL; | |
| 196 | − total = 0; | |
| 197 | − | |
| 198 | − for (i = 0; i < mm->n_roots; ++i) { | |
| 199 | − struct i915_buddy_block *block; | |
| 200 | − unsigned int order; | |
| 201 | − | |
| 202 | − root = mm->roots[i]; | |
| 203 | − if (!root) { | |
| 204 | − pr_err("root(%u) is NULL\n", i); | |
| 205 | − err = -EINVAL; | |
| 206 | − break; | |
| 207 | − } | |
| 208 | − | |
| 209 | − err = igt_check_block(mm, root); | |
| 210 | − | |
| 211 | − if (!i915_buddy_block_is_free(root)) { | |
| 212 | − pr_err("root not free\n"); | |
| 213 | − err = -EINVAL; | |
| 214 | − } | |
| 215 | − | |
| 216 | − order = i915_buddy_block_order(root); | |
| 217 | − | |
| 218 | − if (!i) { | |
| 219 | − if (order != mm->max_order) { | |
| 220 | − pr_err("max order root missing\n"); | |
| 221 | − err = -EINVAL; | |
| 222 | − } | |
| 223 | − } | |
| 224 | − | |
| 225 | − if (prev) { | |
| 226 | − u64 prev_block_size; | |
| 227 | − u64 prev_offset; | |
| 228 | − u64 offset; | |
| 229 | − | |
| 230 | − prev_offset = i915_buddy_block_offset(prev); | |
| 231 | − prev_block_size = i915_buddy_block_size(mm, prev); | |
| 232 | − offset = i915_buddy_block_offset(root); | |
| 233 | − | |
| 234 | − if (offset != (prev_offset + prev_block_size)) { | |
| 235 | − pr_err("root offset mismatch\n"); | |
| 236 | − err = -EINVAL; | |
| 237 | − } | |
| 238 | − } | |
| 239 | − | |
| 240 | − block = list_first_entry_or_null(&mm->free_list[order], | |
| 241 | − struct i915_buddy_block, | |
| 242 | − link); | |
| 243 | − if (block != root) { | |
| 244 | − pr_err("root mismatch at order=%u\n", order); | |
| 245 | − err = -EINVAL; | |
| 246 | − } | |
| 247 | − | |
| 248 | − if (err) | |
| 249 | − break; | |
| 250 | − | |
| 251 | − prev = root; | |
| 252 | − total += i915_buddy_block_size(mm, root); | |
| 253 | − } | |
| 254 | − | |
| 255 | − if (!err) { | |
| 256 | − if (total != mm->size) { | |
| 257 | − pr_err("expected mm size=%llx, found=%llx\n", mm->size, | |
| 258 | − total); | |
| 259 | − err = -EINVAL; | |
| 260 | − } | |
| 261 | − return err; | |
| 262 | − } | |
| 263 | − | |
| 264 | − if (prev) { | |
| 265 | − pr_err("prev root(%u), dump:\n", i - 1); | |
| 266 | − igt_dump_block(mm, prev); | |
| 267 | − } | |
| 268 | − | |
| 269 | − if (root) { | |
| 270 | − pr_err("bad root(%u), dump:\n", i); | |
| 271 | − igt_dump_block(mm, root); | |
| 272 | − } | |
| 273 | − | |
| 274 | − return err; | |
| 275 | −} | |
| 276 | − | |
| 277 | −static void igt_mm_config(u64 *size, u64 *chunk_size) | |
| 278 | −{ | |
| 279 | − I915_RND_STATE(prng); | |
| 280 | − u32 s, ms; | |
| 281 | − | |
| 282 | − /* Nothing fancy, just try to get an interesting bit pattern */ | |
| 283 | − | |
| 284 | − prandom_seed_state(&prng, i915_selftest.random_seed); | |
| 285 | − | |
| 286 | − /* Let size be a random number of pages up to 8 GB (2M pages) */ | |
| 287 | − s = 1 + i915_prandom_u32_max_state((BIT(33 - 12)) - 1, &prng); | |
| 288 | − /* Let the chunk size be a random power of 2 less than size */ | |
| 289 | − ms = BIT(i915_prandom_u32_max_state(ilog2(s), &prng)); | |
| 290 | − /* Round size down to the chunk size */ | |
| 291 | − s &= -ms; | |
| 292 | − | |
| 293 | − /* Convert from pages to bytes */ | |
| 294 | − *chunk_size = (u64)ms << 12; | |
| 295 | − *size = (u64)s << 12; | |
| 296 | −} | |
| 297 | − | |
| 298 | −static int igt_buddy_alloc_smoke(void *arg) | |
| 299 | −{ | |
| 300 | − struct i915_buddy_mm mm; | |
| 301 | − IGT_TIMEOUT(end_time); | |
| 302 | − I915_RND_STATE(prng); | |
| 303 | − u64 chunk_size; | |
| 304 | − u64 mm_size; | |
| 305 | − int *order; | |
| 306 | − int err, i; | |
| 307 | − | |
| 308 | − igt_mm_config(&mm_size, &chunk_size); | |
| 309 | − | |
| 310 | − pr_info("buddy_init with size=%llx, chunk_size=%llx\n", mm_size, chunk_size); | |
| 311 | − | |
| 312 | − err = i915_buddy_init(&mm, mm_size, chunk_size); | |
| 313 | − if (err) { | |
| 314 | − pr_err("buddy_init failed(%d)\n", err); | |
| 315 | − return err; | |
| 316 | − } | |
| 317 | − | |
| 318 | − order = i915_random_order(mm.max_order + 1, &prng); | |
| 319 | − if (!order) | |
| 320 | − goto out_fini; | |
| 321 | − | |
| 322 | − for (i = 0; i <= mm.max_order; ++i) { | |
| 323 | − struct i915_buddy_block *block; | |
| 324 | − int max_order = order[i]; | |
| 325 | − bool timeout = false; | |
| 326 | − LIST_HEAD(blocks); | |
| 327 | − int order; | |
| 328 | − u64 total; | |
| 329 | − | |
| 330 | − err = igt_check_mm(&mm); | |
| 331 | − if (err) { | |
| 332 | − pr_err("pre-mm check failed, abort\n"); | |
| 333 | − break; | |
| 334 | − } | |
| 335 | − | |
| 336 | − pr_info("filling from max_order=%u\n", max_order); | |
| 337 | − | |
| 338 | − order = max_order; | |
| 339 | − total = 0; | |
| 340 | − | |
| 341 | − do { | |
| 342 | −retry: | |
| 343 | − block = i915_buddy_alloc(&mm, order); | |
| 344 | − if (IS_ERR(block)) { | |
| 345 | − err = PTR_ERR(block); | |
| 346 | − if (err == -ENOMEM) { | |
| 347 | − pr_info("buddy_alloc hit -ENOMEM with order=%d\n", | |
| 348 | − order); | |
| 349 | − } else { | |
| 350 | − if (order--) { | |
| 351 | − err = 0; | |
| 352 | − goto retry; | |
| 353 | − } | |
| 354 | − | |
| 355 | − pr_err("buddy_alloc with order=%d failed(%d)\n", | |
| 356 | − order, err); | |
| 357 | − } | |
| 358 | − | |
| 359 | − break; | |
| 360 | − } | |
| 361 | − | |
| 362 | − list_add_tail(&block->link, &blocks); | |
| 363 | − | |
| 364 | − if (i915_buddy_block_order(block) != order) { | |
| 365 | − pr_err("buddy_alloc order mismatch\n"); | |
| 366 | − err = -EINVAL; | |
| 367 | − break; | |
| 368 | − } | |
| 369 | − | |
| 370 | − total += i915_buddy_block_size(&mm, block); | |
| 371 | − | |
| 372 | − if (__igt_timeout(end_time, NULL)) { | |
| 373 | − timeout = true; | |
| 374 | − break; | |
| 375 | − } | |
| 376 | − } while (total < mm.size); | |
| 377 | − | |
| 378 | − if (!err) | |
| 379 | − err = igt_check_blocks(&mm, &blocks, total, false); | |
| 380 | − | |
| 381 | − i915_buddy_free_list(&mm, &blocks); | |
| 382 | − | |
| 383 | − if (!err) { | |
| 384 | − err = igt_check_mm(&mm); | |
| 385 | − if (err) | |
| 386 | − pr_err("post-mm check failed\n"); | |
| 387 | − } | |
| 388 | − | |
| 389 | − if (err || timeout) | |
| 390 | − break; | |
| 391 | − | |
| 392 | − cond_resched(); | |
| 393 | − } | |
| 394 | − | |
| 395 | − if (err == -ENOMEM) | |
| 396 | − err = 0; | |
| 397 | − | |
| 398 | − kfree(order); | |
| 399 | −out_fini: | |
| 400 | − i915_buddy_fini(&mm); | |
| 401 | − | |
| 402 | − return err; | |
| 403 | −} | |
| 404 | − | |
| 405 | −static int igt_buddy_alloc_pessimistic(void *arg) | |
| 406 | −{ | |
| 407 | − const unsigned int max_order = 16; | |
| 408 | − struct i915_buddy_block *block, *bn; | |
| 409 | − struct i915_buddy_mm mm; | |
| 410 | − unsigned int order; | |
| 411 | − LIST_HEAD(blocks); | |
| 412 | − int err; | |
| 413 | − | |
| 414 | − /* | |
| 415 | − * Create a pot-sized mm, then allocate one of each possible | |
| 416 | − * order within. This should leave the mm with exactly one | |
| 417 | − * page left. | |
| 418 | − */ | |
| 419 | − | |
| 420 | − err = i915_buddy_init(&mm, PAGE_SIZE << max_order, PAGE_SIZE); | |
| 421 | − if (err) { | |
| 422 | − pr_err("buddy_init failed(%d)\n", err); | |
| 423 | − return err; | |
| 424 | − } | |
| 425 | − GEM_BUG_ON(mm.max_order != max_order); | |
| 426 | − | |
| 427 | − for (order = 0; order < max_order; order++) { | |
| 428 | − block = i915_buddy_alloc(&mm, order); | |
| 429 | − if (IS_ERR(block)) { | |
| 430 | − pr_info("buddy_alloc hit -ENOMEM with order=%d\n", | |
| 431 | − order); | |
| 432 | − err = PTR_ERR(block); | |
| 433 | − goto err; | |
| 434 | − } | |
| 435 | − | |
| 436 | − list_add_tail(&block->link, &blocks); | |
| 437 | − } | |
| 438 | − | |
| 439 | − /* And now the last remaining block available */ | |
| 440 | − block = i915_buddy_alloc(&mm, 0); | |
| 441 | − if (IS_ERR(block)) { | |
| 442 | − pr_info("buddy_alloc hit -ENOMEM on final alloc\n"); | |
| 443 | − err = PTR_ERR(block); | |
| 444 | − goto err; | |
| 445 | − } | |
| 446 | − list_add_tail(&block->link, &blocks); | |
| 447 | − | |
| 448 | − /* Should be completely full! */ | |
| 449 | − for (order = max_order; order--; ) { | |
| 450 | − block = i915_buddy_alloc(&mm, order); | |
| 451 | − if (!IS_ERR(block)) { | |
| 452 | − pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!", | |
| 453 | − order); | |
| 454 | − list_add_tail(&block->link, &blocks); | |
| 455 | − err = -EINVAL; | |
| 456 | − goto err; | |
| 457 | − } | |
| 458 | − } | |
| 459 | − | |
| 460 | − block = list_last_entry(&blocks, typeof(*block), link); | |
| 461 | − list_del(&block->link); | |
| 462 | − i915_buddy_free(&mm, block); | |
| 463 | − | |
| 464 | − /* As we free in increasing size, we make available larger blocks */ | |
| 465 | − order = 1; | |
| 466 | − list_for_each_entry_safe(block, bn, &blocks, link) { | |
| 467 | − list_del(&block->link); | |
| 468 | − i915_buddy_free(&mm, block); | |
| 469 | − | |
| 470 | − block = i915_buddy_alloc(&mm, order); | |
| 471 | − if (IS_ERR(block)) { | |
| 472 | − pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n", | |
| 473 | − order); | |
| 474 | − err = PTR_ERR(block); | |
| 475 | − goto err; | |
| 476 | − } | |
| 477 | − i915_buddy_free(&mm, block); | |
| 478 | − order++; | |
| 479 | − } | |
| 480 | − | |
| 481 | − /* To confirm, now the whole mm should be available */ | |
| 482 | − block = i915_buddy_alloc(&mm, max_order); | |
| 483 | − if (IS_ERR(block)) { | |
| 484 | − pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n", | |
| 485 | − max_order); | |
| 486 | − err = PTR_ERR(block); | |
| 487 | − goto err; | |
| 488 | − } | |
| 489 | − i915_buddy_free(&mm, block); | |
| 490 | − | |
| 491 | −err: | |
| 492 | − i915_buddy_free_list(&mm, &blocks); | |
| 493 | − i915_buddy_fini(&mm); | |
| 494 | − return err; | |
| 495 | −} | |
| 496 | − | |
| 497 | −static int igt_buddy_alloc_optimistic(void *arg) | |
| 498 | −{ | |
| 499 | − const int max_order = 16; | |
| 500 | − struct i915_buddy_block *block; | |
| 501 | − struct i915_buddy_mm mm; | |
| 502 | − LIST_HEAD(blocks); | |
| 503 | − int order; | |
| 504 | − int err; | |
| 505 | − | |
| 506 | − /* | |
| 507 | − * Create a mm with one block of each order available, and | |
| 508 | − * try to allocate them all. | |
| 509 | − */ | |
| 510 | − | |
| 511 | − err = i915_buddy_init(&mm, | |
| 512 | − PAGE_SIZE * ((1 << (max_order + 1)) - 1), | |
| 513 | − PAGE_SIZE); | |
| 514 | − if (err) { | |
| 515 | − pr_err("buddy_init failed(%d)\n", err); | |
| 516 | − return err; | |
| 517 | − } | |
| 518 | − GEM_BUG_ON(mm.max_order != max_order); | |
| 519 | − | |
| 520 | − for (order = 0; order <= max_order; order++) { | |
| 521 | − block = i915_buddy_alloc(&mm, order); | |
| 522 | − if (IS_ERR(block)) { | |
| 523 | − pr_info("buddy_alloc hit -ENOMEM with order=%d\n", | |
| 524 | − order); | |
| 525 | − err = PTR_ERR(block); | |
| 526 | − goto err; | |
| 527 | − } | |
| 528 | − | |
| 529 | − list_add_tail(&block->link, &blocks); | |
| 530 | − } | |
| 531 | − | |
| 532 | − /* Should be completely full! */ | |
| 533 | − block = i915_buddy_alloc(&mm, 0); | |
| 534 | − if (!IS_ERR(block)) { | |
| 535 | − pr_info("buddy_alloc unexpectedly succeeded, it should be full!"); | |
| 536 | − list_add_tail(&block->link, &blocks); | |
| 537 | − err = -EINVAL; | |
| 538 | − goto err; | |
| 539 | − } | |
| 540 | − | |
| 541 | −err: | |
| 542 | − i915_buddy_free_list(&mm, &blocks); | |
| 543 | − i915_buddy_fini(&mm); | |
| 544 | − return err; | |
| 545 | −} | |
| 546 | − | |
| 547 | −static int igt_buddy_alloc_pathological(void *arg) | |
| 548 | −{ | |
| 549 | − const int max_order = 16; | |
| 550 | − struct i915_buddy_block *block; | |
| 551 | − struct i915_buddy_mm mm; | |
| 552 | − LIST_HEAD(blocks); | |
| 553 | − LIST_HEAD(holes); | |
| 554 | − int order, top; | |
| 555 | − int err; | |
| 556 | − | |
| 557 | − /* | |
| 558 | − * Create a pot-sized mm, then allocate one of each possible | |
| 559 | − * order within. This should leave the mm with exactly one | |
| 560 | − * page left. Free the largest block, then whittle down again. | |
| 561 | − * Eventually we will have a fully 50% fragmented mm. | |
| 562 | − */ | |
| 563 | − | |
| 564 | − err = i915_buddy_init(&mm, PAGE_SIZE << max_order, PAGE_SIZE); | |
| 565 | − if (err) { | |
| 566 | − pr_err("buddy_init failed(%d)\n", err); | |
| 567 | − return err; | |
| 568 | − } | |
| 569 | − GEM_BUG_ON(mm.max_order != max_order); | |
| 570 | − | |
| 571 | − for (top = max_order; top; top--) { | |
| 572 | − /* Make room by freeing the largest allocated block */ | |
| 573 | − block = list_first_entry_or_null(&blocks, typeof(*block), link); | |
| 574 | − if (block) { | |
| 575 | − list_del(&block->link); | |
| 576 | − i915_buddy_free(&mm, block); | |
| 577 | − } | |
| 578 | − | |
| 579 | − for (order = top; order--; ) { | |
| 580 | − block = i915_buddy_alloc(&mm, order); | |
| 581 | − if (IS_ERR(block)) { | |
| 582 | − pr_info("buddy_alloc hit -ENOMEM with order=%d, top=%d\n", | |
| 583 | − order, top); | |
| 584 | − err = PTR_ERR(block); | |
| 585 | − goto err; | |
| 586 | − } | |
| 587 | − list_add_tail(&block->link, &blocks); | |
| 588 | − } | |
| 589 | − | |
| 590 | − /* There should be one final page for this sub-allocation */ | |
| 591 | − block = i915_buddy_alloc(&mm, 0); | |
| 592 | − if (IS_ERR(block)) { | |
| 593 | − pr_info("buddy_alloc hit -ENOMEM for hole\n"); | |
| 594 | − err = PTR_ERR(block); | |
| 595 | − goto err; | |
| 596 | − } | |
| 597 | − list_add_tail(&block->link, &holes); | |
| 598 | − | |
| 599 | − block = i915_buddy_alloc(&mm, top); | |
| 600 | − if (!IS_ERR(block)) { | |
| 601 | − pr_info("buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!", | |
| 602 | − top, max_order); | |
| 603 | − list_add_tail(&block->link, &blocks); | |
| 604 | − err = -EINVAL; | |
| 605 | − goto err; | |
| 606 | − } | |
| 607 | − } | |
| 608 | − | |
| 609 | − i915_buddy_free_list(&mm, &holes); | |
| 610 | − | |
| 611 | − /* Nothing larger than blocks of chunk_size now available */ | |
| 612 | − for (order = 1; order <= max_order; order++) { | |
| 613 | − block = i915_buddy_alloc(&mm, order); | |
| 614 | − if (!IS_ERR(block)) { | |
| 615 | − pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!", | |
| 616 | − order); | |
| 617 | − list_add_tail(&block->link, &blocks); | |
| 618 | − err = -EINVAL; | |
| 619 | − goto err; | |
| 620 | − } | |
| 621 | − } | |
| 622 | − | |
| 623 | −err: | |
| 624 | − list_splice_tail(&holes, &blocks); | |
| 625 | − i915_buddy_free_list(&mm, &blocks); | |
| 626 | − i915_buddy_fini(&mm); | |
| 627 | − return err; | |
| 628 | −} | |
| 629 | − | |
| 630 | −static int igt_buddy_alloc_range(void *arg) | |
| 631 | −{ | |
| 632 | − struct i915_buddy_mm mm; | |
| 633 | − unsigned long page_num; | |
| 634 | − LIST_HEAD(blocks); | |
| 635 | − u64 chunk_size; | |
| 636 | − u64 offset; | |
| 637 | − u64 size; | |
| 638 | − u64 rem; | |
| 639 | − int err; | |
| 640 | − | |
| 641 | − igt_mm_config(&size, &chunk_size); | |
| 642 | − | |
| 643 | − pr_info("buddy_init with size=%llx, chunk_size=%llx\n", size, chunk_size); | |
| 644 | − | |
| 645 | − err = i915_buddy_init(&mm, size, chunk_size); | |
| 646 | − if (err) { | |
| 647 | − pr_err("buddy_init failed(%d)\n", err); | |
| 648 | − return err; | |
| 649 | − } | |
| 650 | − | |
| 651 | − err = igt_check_mm(&mm); | |
| 652 | − if (err) { | |
| 653 | − pr_err("pre-mm check failed, abort, abort, abort!\n"); | |
| 654 | − goto err_fini; | |
| 655 | − } | |
| 656 | − | |
| 657 | − rem = mm.size; | |
| 658 | − offset = 0; | |
| 659 | − | |
| 660 | − for_each_prime_number_from(page_num, 1, ULONG_MAX - 1) { | |
| 661 | − struct i915_buddy_block *block; | |
| 662 | − LIST_HEAD(tmp); | |
| 663 | − | |
| 664 | − size = min(page_num * mm.chunk_size, rem); | |
| 665 | − | |
| 666 | − err = i915_buddy_alloc_range(&mm, &tmp, offset, size); | |
| 667 | − if (err) { | |
| 668 | − if (err == -ENOMEM) { | |
| 669 | − pr_info("alloc_range hit -ENOMEM with size=%llx\n", | |
| 670 | − size); | |
| 671 | − } else { | |
| 672 | − pr_err("alloc_range with offset=%llx, size=%llx failed(%d)\n", | |
| 673 | − offset, size, err); | |
| 674 | − } | |
| 675 | − | |
| 676 | − break; | |
| 677 | − } | |
| 678 | − | |
| 679 | − block = list_first_entry_or_null(&tmp, | |
| 680 | − struct i915_buddy_block, | |
| 681 | − link); | |
| 682 | − if (!block) { | |
| 683 | − pr_err("alloc_range has no blocks\n"); | |
| 684 | − err = -EINVAL; | |
| 685 | − break; | |
| 686 | − } | |
| 687 | − | |
| 688 | − if (i915_buddy_block_offset(block) != offset) { | |
| 689 | − pr_err("alloc_range start offset mismatch, found=%llx, expected=%llx\n", | |
| 690 | − i915_buddy_block_offset(block), offset); | |
| 691 | − err = -EINVAL; | |
| 692 | − } | |
| 693 | − | |
| 694 | − if (!err) | |
| 695 | − err = igt_check_blocks(&mm, &tmp, size, true); | |
| 696 | − | |
| 697 | − list_splice_tail(&tmp, &blocks); | |
| 698 | − | |
| 699 | − if (err) | |
| 700 | − break; | |
| 701 | − | |
| 702 | − offset += size; | |
| 703 | − | |
| 704 | − rem -= size; | |
| 705 | − if (!rem) | |
| 706 | − break; | |
| 707 | − | |
| 708 | − cond_resched(); | |
| 709 | − } | |
| 710 | − | |
| 711 | − if (err == -ENOMEM) | |
| 712 | − err = 0; | |
| 713 | − | |
| 714 | − i915_buddy_free_list(&mm, &blocks); | |
| 715 | − | |
| 716 | − if (!err) { | |
| 717 | − err = igt_check_mm(&mm); | |
| 718 | − if (err) | |
| 719 | − pr_err("post-mm check failed\n"); | |
| 720 | − } | |
| 721 | − | |
| 722 | −err_fini: | |
| 723 | − i915_buddy_fini(&mm); | |
| 724 | − | |
| 725 | − return err; | |
| 726 | −} | |
| 727 | − | |
| 728 | −static int igt_buddy_alloc_limit(void *arg) | |
| 729 | −{ | |
| 730 | − struct i915_buddy_block *block; | |
| 731 | − struct i915_buddy_mm mm; | |
| 732 | − const u64 size = U64_MAX; | |
| 733 | − int err; | |
| 734 | − | |
| 735 | − err = i915_buddy_init(&mm, size, PAGE_SIZE); | |
| 736 | − if (err) | |
| 737 | − return err; | |
| 738 | − | |
| 739 | − if (mm.max_order != I915_BUDDY_MAX_ORDER) { | |
| 740 | − pr_err("mm.max_order(%d) != %d\n", | |
| 741 | − mm.max_order, I915_BUDDY_MAX_ORDER); | |
| 742 | − err = -EINVAL; | |
| 743 | − goto out_fini; | |
| 744 | − } | |
| 745 | − | |
| 746 | − block = i915_buddy_alloc(&mm, mm.max_order); | |
| 747 | − if (IS_ERR(block)) { | |
| 748 | − err = PTR_ERR(block); | |
| 749 | − goto out_fini; | |
| 750 | − } | |
| 751 | − | |
| 752 | − if (i915_buddy_block_order(block) != mm.max_order) { | |
| 753 | − pr_err("block order(%d) != %d\n", | |
| 754 | − i915_buddy_block_order(block), mm.max_order); | |
| 755 | − err = -EINVAL; | |
| 756 | − goto out_free; | |
| 757 | − } | |
| 758 | − | |
| 759 | − if (i915_buddy_block_size(&mm, block) != | |
| 760 | − BIT_ULL(mm.max_order) * PAGE_SIZE) { | |
| 761 | − pr_err("block size(%llu) != %llu\n", | |
| 762 | − i915_buddy_block_size(&mm, block), | |
| 763 | − BIT_ULL(mm.max_order) * PAGE_SIZE); | |
| 764 | − err = -EINVAL; | |
| 765 | − goto out_free; | |
| 766 | − } | |
| 767 | − | |
| 768 | −out_free: | |
| 769 | − i915_buddy_free(&mm, block); | |
| 770 | −out_fini: | |
| 771 | − i915_buddy_fini(&mm); | |
| 772 | − return err; | |
| 773 | −} | |
| 774 | − | |
| 775 | −int i915_buddy_mock_selftests(void) | |
| 776 | −{ | |
| 777 | − static const struct i915_subtest tests[] = { | |
| 778 | − SUBTEST(igt_buddy_alloc_pessimistic), | |
| 779 | − SUBTEST(igt_buddy_alloc_optimistic), | |
| 780 | − SUBTEST(igt_buddy_alloc_pathological), | |
| 781 | − SUBTEST(igt_buddy_alloc_smoke), | |
| 782 | − SUBTEST(igt_buddy_alloc_range), | |
| 783 | − SUBTEST(igt_buddy_alloc_limit), | |
| 784 | − }; | |
| 785 | − | |
| 786 | − return i915_subtests(tests, NULL); | |
| 787 | −} | |
| @@ -33,4 +33,3 @@ selftest(evict, i915_gem_evict_mock_selftests) · 32 unmodified lines | ||
| 33 | 33 | selftest(gtt, i915_gem_gtt_mock_selftests) |
| 34 | 34 | selftest(hugepages, i915_gem_huge_page_mock_selftests) |
| 35 | 35 | selftest(memory_region, intel_memory_region_mock_selftests) |
| 36 | −selftest(buddy, i915_buddy_mock_selftests) | |
| @@ -6,6 +6,8 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <linux/prime_numbers.h> |
| 7 | 7 | #include <linux/sort.h> |
| 8 | 8 | |
| 9 | +#include <drm/drm_buddy.h> | |
| 10 | + | |
| 9 | 11 | #include "../i915_selftest.h" |
| 10 | 12 | |
| 11 | 13 | #include "mock_drm.h" |
| @@ -20,7 +22,6 @@ · 8 unmodified lines | ||
| 20 | 22 | #include "gt/intel_engine_pm.h" |
| 21 | 23 | #include "gt/intel_engine_user.h" |
| 22 | 24 | #include "gt/intel_gt.h" |
| 23 | −#include "i915_buddy.h" | |
| 24 | 25 | #include "gt/intel_migrate.h" |
| 25 | 26 | #include "i915_memcpy.h" |
| 26 | 27 | #include "i915_ttm_buddy_manager.h" |
| @@ -369,7 +370,7 @@ static int igt_mock_splintered_region(void *arg) · 342 unmodified lines | ||
| 369 | 370 | struct drm_i915_private *i915 = mem->i915; |
| 370 | 371 | struct i915_ttm_buddy_resource *res; |
| 371 | 372 | struct drm_i915_gem_object *obj; |
| 372 | − struct i915_buddy_mm *mm; | |
| 373 | + struct drm_buddy *mm; | |
| 373 | 374 | unsigned int expected_order; |
| 374 | 375 | LIST_HEAD(objects); |
| 375 | 376 | u64 size; |
| @@ -454,8 +455,8 @@ static int igt_mock_max_segment(void *arg) · 78 unmodified lines | ||
| 454 | 455 | struct drm_i915_private *i915 = mem->i915; |
| 455 | 456 | struct i915_ttm_buddy_resource *res; |
| 456 | 457 | struct drm_i915_gem_object *obj; |
| 457 | − struct i915_buddy_block *block; | |
| 458 | − struct i915_buddy_mm *mm; | |
| 458 | + struct drm_buddy_block *block; | |
| 459 | + struct drm_buddy *mm; | |
| 459 | 460 | struct list_head *blocks; |
| 460 | 461 | struct scatterlist *sg; |
| 461 | 462 | LIST_HEAD(objects); |
| @@ -485,8 +486,8 @@ static int igt_mock_max_segment(void *arg) · 23 unmodified lines | ||
| 485 | 486 | mm = res->mm; |
| 486 | 487 | size = 0; |
| 487 | 488 | list_for_each_entry(block, blocks, link) { |
| 488 | − if (i915_buddy_block_size(mm, block) > size) | |
| 489 | − size = i915_buddy_block_size(mm, block); | |
| 489 | + if (drm_buddy_block_size(mm, block) > size) | |
| 490 | + size = drm_buddy_block_size(mm, block); | |
| 490 | 491 | } |
| 491 | 492 | if (size < max_segment) { |
| 492 | 493 | pr_err("%s: Failed to create a huge contiguous block [> %u], largest block %lld\n", |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <linux/module.h> |
| 7 | 7 | #include <linux/kernel.h> |
| 8 | 8 | #include <linux/platform_device.h> |
| 9 | +#include <drm/drm_module.h> | |
| 9 | 10 | #include <drm/drm_of.h> |
| 10 | 11 | |
| 11 | 12 | #include "dcss-dev.h" |
| @@ -131,7 +132,7 @@ static struct platform_driver dcss_platform_driver = { · 119 unmodified lines | ||
| 131 | 132 | }, |
| 132 | 133 | }; |
| 133 | 134 | |
| 134 | −module_platform_driver(dcss_platform_driver); | |
| 135 | +drm_module_platform_driver(dcss_platform_driver); | |
| 135 | 136 | |
| 136 | 137 | MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@nxp.com>"); |
| 137 | 138 | MODULE_DESCRIPTION("DCSS driver for i.MX8MQ"); |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | #include "ingenic-drm.h" |
| 8 | 8 | |
| 9 | +#include <linux/bitfield.h> | |
| 9 | 10 | #include <linux/component.h> |
| 10 | 11 | #include <linux/clk.h> |
| 11 | 12 | #include <linux/dma-mapping.h> |
| @@ -49,6 +50,11 @@ struct ingenic_dma_hwdesc { · 37 unmodified lines | ||
| 49 | 50 | u32 addr; |
| 50 | 51 | u32 id; |
| 51 | 52 | u32 cmd; |
| 53 | + /* extended hw descriptor for jz4780 */ | |
| 54 | + u32 offsize; | |
| 55 | + u32 pagewidth; | |
| 56 | + u32 cpos; | |
| 57 | + u32 dessize; | |
| 52 | 58 | } __aligned(16); |
| 53 | 59 | |
| 54 | 60 | struct ingenic_dma_hwdescs { |
| @@ -60,6 +66,7 @@ struct jz_soc_info { · 5 unmodified lines | ||
| 60 | 66 | bool needs_dev_clk; |
| 61 | 67 | bool has_osd; |
| 62 | 68 | bool map_noncoherent; |
| 69 | + bool use_extended_hwdesc; | |
| 63 | 70 | unsigned int max_width, max_height; |
| 64 | 71 | const u32 *formats_f0, *formats_f1; |
| 65 | 72 | unsigned int num_formats_f0, num_formats_f1; |
| @@ -173,7 +180,6 @@ static const struct regmap_config ingenic_drm_regmap_config = { · 107 unmodified lines | ||
| 173 | 180 | .val_bits = 32, |
| 174 | 181 | .reg_stride = 4, |
| 175 | 182 | |
| 176 | − .max_register = JZ_REG_LCD_SIZE1, | |
| 177 | 183 | .writeable_reg = ingenic_drm_writeable_reg, |
| 178 | 184 | }; |
| 179 | 185 | |
| @@ -447,6 +453,9 @@ static int ingenic_drm_plane_atomic_check(struct drm_plane *plane, · 267 unmodified lines | ||
| 447 | 453 | if (!crtc) |
| 448 | 454 | return 0; |
| 449 | 455 | |
| 456 | + if (plane == &priv->f0) | |
| 457 | + return -EINVAL; | |
| 458 | + | |
| 450 | 459 | crtc_state = drm_atomic_get_existing_crtc_state(state, |
| 451 | 460 | crtc); |
| 452 | 461 | if (WARN_ON(!crtc_state)) |
| @@ -663,6 +672,33 @@ static void ingenic_drm_plane_atomic_update(struct drm_plane *plane, · 210 unmodified lines | ||
| 663 | 672 | hwdesc->cmd = JZ_LCD_CMD_EOF_IRQ | (width * height * cpp / 4); |
| 664 | 673 | hwdesc->next = dma_hwdesc_addr(priv, next_id); |
| 665 | 674 | |
| 675 | + if (priv->soc_info->use_extended_hwdesc) { | |
| 676 | + hwdesc->cmd |= JZ_LCD_CMD_FRM_ENABLE; | |
| 677 | + | |
| 678 | + /* Extended 8-byte descriptor */ | |
| 679 | + hwdesc->cpos = 0; | |
| 680 | + hwdesc->offsize = 0; | |
| 681 | + hwdesc->pagewidth = 0; | |
| 682 | + | |
| 683 | + switch (newstate->fb->format->format) { | |
| 684 | + case DRM_FORMAT_XRGB1555: | |
| 685 | + hwdesc->cpos |= JZ_LCD_CPOS_RGB555; | |
| 686 | + fallthrough; | |
| 687 | + case DRM_FORMAT_RGB565: | |
| 688 | + hwdesc->cpos |= JZ_LCD_CPOS_BPP_15_16; | |
| 689 | + break; | |
| 690 | + case DRM_FORMAT_XRGB8888: | |
| 691 | + hwdesc->cpos |= JZ_LCD_CPOS_BPP_18_24; | |
| 692 | + break; | |
| 693 | + } | |
| 694 | + hwdesc->cpos |= (JZ_LCD_CPOS_COEFFICIENT_1 << | |
| 695 | + JZ_LCD_CPOS_COEFFICIENT_OFFSET); | |
| 696 | + hwdesc->dessize = | |
| 697 | + (0xff << JZ_LCD_DESSIZE_ALPHA_OFFSET) | | |
| 698 | + FIELD_PREP(JZ_LCD_DESSIZE_HEIGHT_MASK, height - 1) | | |
| 699 | + FIELD_PREP(JZ_LCD_DESSIZE_WIDTH_MASK, width - 1); | |
| 700 | + } | |
| 701 | + | |
| 666 | 702 | if (drm_atomic_crtc_needs_modeset(crtc_state)) { |
| 667 | 703 | fourcc = newstate->fb->format->format; |
| 668 | 704 | |
| @@ -694,6 +730,9 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, · 25 unmodified lines | ||
| 694 | 730 | | JZ_LCD_CFG_SPL_DISABLE | JZ_LCD_CFG_REV_DISABLE; |
| 695 | 731 | } |
| 696 | 732 | |
| 733 | + if (priv->soc_info->use_extended_hwdesc) | |
| 734 | + cfg |= JZ_LCD_CFG_DESCRIPTOR_8; | |
| 735 | + | |
| 697 | 736 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) |
| 698 | 737 | cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW; |
| 699 | 738 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
| @@ -1011,6 +1050,8 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) · 311 unmodified lines | ||
| 1011 | 1050 | struct ingenic_drm_bridge *ib; |
| 1012 | 1051 | struct drm_device *drm; |
| 1013 | 1052 | void __iomem *base; |
| 1053 | + struct resource *res; | |
| 1054 | + struct regmap_config regmap_config; | |
| 1014 | 1055 | long parent_rate; |
| 1015 | 1056 | unsigned int i, clone_mask = 0; |
| 1016 | 1057 | int ret, irq; |
| @@ -1056,14 +1097,16 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) · 39 unmodified lines | ||
| 1056 | 1097 | drm->mode_config.funcs = &ingenic_drm_mode_config_funcs; |
| 1057 | 1098 | drm->mode_config.helper_private = &ingenic_drm_mode_config_helpers; |
| 1058 | 1099 | |
| 1059 | − base = devm_platform_ioremap_resource(pdev, 0); | |
| 1100 | + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); | |
| 1060 | 1101 | if (IS_ERR(base)) { |
| 1061 | 1102 | dev_err(dev, "Failed to get memory resource\n"); |
| 1062 | 1103 | return PTR_ERR(base); |
| 1063 | 1104 | } |
| 1064 | 1105 | |
| 1106 | + regmap_config = ingenic_drm_regmap_config; | |
| 1107 | + regmap_config.max_register = res->end - res->start; | |
| 1065 | 1108 | priv->map = devm_regmap_init_mmio(dev, base, |
| 1066 | − &ingenic_drm_regmap_config); | |
| 1109 | + ®map_config); | |
| 1067 | 1110 | if (IS_ERR(priv->map)) { |
| 1068 | 1111 | dev_err(dev, "Failed to create regmap\n"); |
| 1069 | 1112 | return PTR_ERR(priv->map); |
| @@ -1465,10 +1508,23 @@ static const struct jz_soc_info jz4770_soc_info = { · 395 unmodified lines | ||
| 1465 | 1508 | .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), |
| 1466 | 1509 | }; |
| 1467 | 1510 | |
| 1511 | +static const struct jz_soc_info jz4780_soc_info = { | |
| 1512 | + .needs_dev_clk = true, | |
| 1513 | + .has_osd = true, | |
| 1514 | + .use_extended_hwdesc = true, | |
| 1515 | + .max_width = 4096, | |
| 1516 | + .max_height = 2048, | |
| 1517 | + .formats_f1 = jz4770_formats_f1, | |
| 1518 | + .num_formats_f1 = ARRAY_SIZE(jz4770_formats_f1), | |
| 1519 | + .formats_f0 = jz4770_formats_f0, | |
| 1520 | + .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), | |
| 1521 | +}; | |
| 1522 | + | |
| 1468 | 1523 | static const struct of_device_id ingenic_drm_of_match[] = { |
| 1469 | 1524 | { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info }, |
| 1470 | 1525 | { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info }, |
| 1471 | 1526 | { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info }, |
| 1527 | + { .compatible = "ingenic,jz4780-lcd", .data = &jz4780_soc_info }, | |
| 1472 | 1528 | { /* sentinel */ }, |
| 1473 | 1529 | }; |
| 1474 | 1530 | MODULE_DEVICE_TABLE(of, ingenic_drm_of_match); |
| @@ -44,8 +44,11 @@ · 43 unmodified lines | ||
| 44 | 44 | #define JZ_REG_LCD_XYP1 0x124 |
| 45 | 45 | #define JZ_REG_LCD_SIZE0 0x128 |
| 46 | 46 | #define JZ_REG_LCD_SIZE1 0x12c |
| 47 | +#define JZ_REG_LCD_PCFG 0x2c0 | |
| 47 | 48 | |
| 48 | 49 | #define JZ_LCD_CFG_SLCD BIT(31) |
| 50 | +#define JZ_LCD_CFG_DESCRIPTOR_8 BIT(28) | |
| 51 | +#define JZ_LCD_CFG_RECOVER_FIFO_UNDERRUN BIT(25) | |
| 49 | 52 | #define JZ_LCD_CFG_PS_DISABLE BIT(23) |
| 50 | 53 | #define JZ_LCD_CFG_CLS_DISABLE BIT(22) |
| 51 | 54 | #define JZ_LCD_CFG_SPL_DISABLE BIT(21) |
| @@ -63,6 +66,7 @@ · 11 unmodified lines | ||
| 63 | 66 | #define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9) |
| 64 | 67 | #define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8) |
| 65 | 68 | #define JZ_LCD_CFG_18_BIT BIT(7) |
| 69 | +#define JZ_LCD_CFG_24_BIT BIT(6) | |
| 66 | 70 | #define JZ_LCD_CFG_PDW (BIT(5) | BIT(4)) |
| 67 | 71 | |
| 68 | 72 | #define JZ_LCD_CFG_MODE_GENERIC_16BIT 0 |
| @@ -132,6 +136,7 @@ · 63 unmodified lines | ||
| 132 | 136 | #define JZ_LCD_CMD_SOF_IRQ BIT(31) |
| 133 | 137 | #define JZ_LCD_CMD_EOF_IRQ BIT(30) |
| 134 | 138 | #define JZ_LCD_CMD_ENABLE_PAL BIT(28) |
| 139 | +#define JZ_LCD_CMD_FRM_ENABLE BIT(26) | |
| 135 | 140 | |
| 136 | 141 | #define JZ_LCD_SYNC_MASK 0x3ff |
| 137 | 142 | |
| @@ -153,6 +158,7 @@ · 15 unmodified lines | ||
| 153 | 158 | #define JZ_LCD_RGBC_EVEN_BGR (0x5 << 0) |
| 154 | 159 | |
| 155 | 160 | #define JZ_LCD_OSDC_OSDEN BIT(0) |
| 161 | +#define JZ_LCD_OSDC_ALPHAEN BIT(2) | |
| 156 | 162 | #define JZ_LCD_OSDC_F0EN BIT(3) |
| 157 | 163 | #define JZ_LCD_OSDC_F1EN BIT(4) |
| 158 | 164 | |
| @@ -176,6 +182,38 @@ · 17 unmodified lines | ||
| 176 | 182 | #define JZ_LCD_SIZE01_WIDTH_LSB 0 |
| 177 | 183 | #define JZ_LCD_SIZE01_HEIGHT_LSB 16 |
| 178 | 184 | |
| 185 | +#define JZ_LCD_DESSIZE_ALPHA_OFFSET 24 | |
| 186 | +#define JZ_LCD_DESSIZE_HEIGHT_MASK GENMASK(23, 12) | |
| 187 | +#define JZ_LCD_DESSIZE_WIDTH_MASK GENMASK(11, 0) | |
| 188 | + | |
| 189 | +#define JZ_LCD_CPOS_BPP_15_16 (4 << 27) | |
| 190 | +#define JZ_LCD_CPOS_BPP_18_24 (5 << 27) | |
| 191 | +#define JZ_LCD_CPOS_BPP_30 (7 << 27) | |
| 192 | +#define JZ_LCD_CPOS_RGB555 BIT(30) | |
| 193 | +#define JZ_LCD_CPOS_PREMULTIPLY_LCD BIT(26) | |
| 194 | +#define JZ_LCD_CPOS_COEFFICIENT_OFFSET 24 | |
| 195 | +#define JZ_LCD_CPOS_COEFFICIENT_0 0 | |
| 196 | +#define JZ_LCD_CPOS_COEFFICIENT_1 1 | |
| 197 | +#define JZ_LCD_CPOS_COEFFICIENT_ALPHA1 2 | |
| 198 | +#define JZ_LCD_CPOS_COEFFICIENT_1_ALPHA1 3 | |
| 199 | + | |
| 200 | +#define JZ_LCD_RGBC_RGB_PADDING BIT(15) | |
| 201 | +#define JZ_LCD_RGBC_RGB_PADDING_FIRST BIT(14) | |
| 202 | +#define JZ_LCD_RGBC_422 BIT(8) | |
| 203 | +#define JZ_LCD_RGBC_RGB_FORMAT_ENABLE BIT(7) | |
| 204 | + | |
| 205 | +#define JZ_LCD_PCFG_PRI_MODE BIT(31) | |
| 206 | +#define JZ_LCD_PCFG_HP_BST_4 (0 << 28) | |
| 207 | +#define JZ_LCD_PCFG_HP_BST_8 (1 << 28) | |
| 208 | +#define JZ_LCD_PCFG_HP_BST_16 (2 << 28) | |
| 209 | +#define JZ_LCD_PCFG_HP_BST_32 (3 << 28) | |
| 210 | +#define JZ_LCD_PCFG_HP_BST_64 (4 << 28) | |
| 211 | +#define JZ_LCD_PCFG_HP_BST_16_CONT (5 << 28) | |
| 212 | +#define JZ_LCD_PCFG_HP_BST_DISABLE (7 << 28) | |
| 213 | +#define JZ_LCD_PCFG_THRESHOLD2_OFFSET 18 | |
| 214 | +#define JZ_LCD_PCFG_THRESHOLD1_OFFSET 9 | |
| 215 | +#define JZ_LCD_PCFG_THRESHOLD0_OFFSET 0 | |
| 216 | + | |
| 179 | 217 | struct device; |
| 180 | 218 | struct drm_plane; |
| 181 | 219 | struct drm_plane_state; |
| @@ -302,42 +302,42 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) · 301 unmodified lines | ||
| 302 | 302 | if (priv->afbcd.ops) { |
| 303 | 303 | ret = priv->afbcd.ops->init(priv); |
| 304 | 304 | if (ret) |
| 305 | − return ret; | |
| 305 | + goto free_drm; | |
| 306 | 306 | } |
| 307 | 307 | |
| 308 | 308 | /* Encoder Initialization */ |
| 309 | 309 | |
| 310 | 310 | ret = meson_encoder_cvbs_init(priv); |
| 311 | 311 | if (ret) |
| 312 | − goto free_drm; | |
| 312 | + goto exit_afbcd; | |
| 313 | 313 | |
| 314 | 314 | if (has_components) { |
| 315 | 315 | ret = component_bind_all(drm->dev, drm); |
| 316 | 316 | if (ret) { |
| 317 | 317 | dev_err(drm->dev, "Couldn't bind all components\n"); |
| 318 | − goto free_drm; | |
| 318 | + goto exit_afbcd; | |
| 319 | 319 | } |
| 320 | 320 | } |
| 321 | 321 | |
| 322 | 322 | ret = meson_encoder_hdmi_init(priv); |
| 323 | 323 | if (ret) |
| 324 | − goto free_drm; | |
| 324 | + goto exit_afbcd; | |
| 325 | 325 | |
| 326 | 326 | ret = meson_plane_create(priv); |
| 327 | 327 | if (ret) |
| 328 | − goto free_drm; | |
| 328 | + goto exit_afbcd; | |
| 329 | 329 | |
| 330 | 330 | ret = meson_overlay_create(priv); |
| 331 | 331 | if (ret) |
| 332 | − goto free_drm; | |
| 332 | + goto exit_afbcd; | |
| 333 | 333 | |
| 334 | 334 | ret = meson_crtc_create(priv); |
| 335 | 335 | if (ret) |
| 336 | − goto free_drm; | |
| 336 | + goto exit_afbcd; | |
| 337 | 337 | |
| 338 | 338 | ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm); |
| 339 | 339 | if (ret) |
| 340 | − goto free_drm; | |
| 340 | + goto exit_afbcd; | |
| 341 | 341 | |
| 342 | 342 | drm_mode_config_reset(drm); |
| 343 | 343 | |
| @@ -355,6 +355,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) · 11 unmodified lines | ||
| 355 | 355 | |
| 356 | 356 | uninstall_irq: |
| 357 | 357 | free_irq(priv->vsync_irq, drm); |
| 358 | +exit_afbcd: | |
| 359 | + if (priv->afbcd.ops) | |
| 360 | + priv->afbcd.ops->exit(priv); | |
| 358 | 361 | free_drm: |
| 359 | 362 | drm_dev_put(drm); |
| 360 | 363 | |
| @@ -385,10 +388,8 @@ static void meson_drv_unbind(struct device *dev) · 24 unmodified lines | ||
| 385 | 388 | free_irq(priv->vsync_irq, drm); |
| 386 | 389 | drm_dev_put(drm); |
| 387 | 390 | |
| 388 | − if (priv->afbcd.ops) { | |
| 389 | − priv->afbcd.ops->reset(priv); | |
| 390 | − meson_rdma_free(priv); | |
| 391 | − } | |
| 391 | + if (priv->afbcd.ops) | |
| 392 | + priv->afbcd.ops->exit(priv); | |
| 392 | 393 | } |
| 393 | 394 | |
| 394 | 395 | static const struct component_master_ops meson_drv_master_ops = { |
| @@ -79,11 +79,6 @@ static bool meson_gxm_afbcd_supported_fmt(u64 modifier, uint32_t format) · 78 unmodified lines | ||
| 79 | 79 | return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0; |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | −static int meson_gxm_afbcd_init(struct meson_drm *priv) | |
| 83 | −{ | |
| 84 | − return 0; | |
| 85 | −} | |
| 86 | − | |
| 87 | 82 | static int meson_gxm_afbcd_reset(struct meson_drm *priv) |
| 88 | 83 | { |
| 89 | 84 | writel_relaxed(VIU_SW_RESET_OSD1_AFBCD, |
| @@ -93,6 +88,16 @@ static int meson_gxm_afbcd_reset(struct meson_drm *priv) · 3 unmodified lines | ||
| 93 | 88 | return 0; |
| 94 | 89 | } |
| 95 | 90 | |
| 91 | +static int meson_gxm_afbcd_init(struct meson_drm *priv) | |
| 92 | +{ | |
| 93 | + return 0; | |
| 94 | +} | |
| 95 | + | |
| 96 | +static void meson_gxm_afbcd_exit(struct meson_drm *priv) | |
| 97 | +{ | |
| 98 | + meson_gxm_afbcd_reset(priv); | |
| 99 | +} | |
| 100 | + | |
| 96 | 101 | static int meson_gxm_afbcd_enable(struct meson_drm *priv) |
| 97 | 102 | { |
| 98 | 103 | writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) | |
| @@ -172,6 +177,7 @@ static int meson_gxm_afbcd_setup(struct meson_drm *priv) · 73 unmodified lines | ||
| 172 | 177 | |
| 173 | 178 | struct meson_afbcd_ops meson_afbcd_gxm_ops = { |
| 174 | 179 | .init = meson_gxm_afbcd_init, |
| 180 | + .exit = meson_gxm_afbcd_exit, | |
| 175 | 181 | .reset = meson_gxm_afbcd_reset, |
| 176 | 182 | .enable = meson_gxm_afbcd_enable, |
| 177 | 183 | .disable = meson_gxm_afbcd_disable, |
| @@ -269,6 +275,18 @@ static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format) · 91 unmodified lines | ||
| 269 | 275 | return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0; |
| 270 | 276 | } |
| 271 | 277 | |
| 278 | +static int meson_g12a_afbcd_reset(struct meson_drm *priv) | |
| 279 | +{ | |
| 280 | + meson_rdma_reset(priv); | |
| 281 | + | |
| 282 | + meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | | |
| 283 | + VIU_SW_RESET_G12A_OSD1_AFBCD, | |
| 284 | + VIU_SW_RESET); | |
| 285 | + meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); | |
| 286 | + | |
| 287 | + return 0; | |
| 288 | +} | |
| 289 | + | |
| 272 | 290 | static int meson_g12a_afbcd_init(struct meson_drm *priv) |
| 273 | 291 | { |
| 274 | 292 | int ret; |
| @@ -286,16 +304,10 @@ static int meson_g12a_afbcd_init(struct meson_drm *priv) · 11 unmodified lines | ||
| 286 | 304 | return 0; |
| 287 | 305 | } |
| 288 | 306 | |
| 289 | −static int meson_g12a_afbcd_reset(struct meson_drm *priv) | |
| 307 | +static void meson_g12a_afbcd_exit(struct meson_drm *priv) | |
| 290 | 308 | { |
| 291 | − meson_rdma_reset(priv); | |
| 292 | − | |
| 293 | − meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | | |
| 294 | − VIU_SW_RESET_G12A_OSD1_AFBCD, | |
| 295 | − VIU_SW_RESET); | |
| 296 | − meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); | |
| 297 | − | |
| 298 | − return 0; | |
| 309 | + meson_g12a_afbcd_reset(priv); | |
| 310 | + meson_rdma_free(priv); | |
| 299 | 311 | } |
| 300 | 312 | |
| 301 | 313 | static int meson_g12a_afbcd_enable(struct meson_drm *priv) |
| @@ -380,6 +392,7 @@ static int meson_g12a_afbcd_setup(struct meson_drm *priv) · 78 unmodified lines | ||
| 380 | 392 | |
| 381 | 393 | struct meson_afbcd_ops meson_afbcd_g12a_ops = { |
| 382 | 394 | .init = meson_g12a_afbcd_init, |
| 395 | + .exit = meson_g12a_afbcd_exit, | |
| 383 | 396 | .reset = meson_g12a_afbcd_reset, |
| 384 | 397 | .enable = meson_g12a_afbcd_enable, |
| 385 | 398 | .disable = meson_g12a_afbcd_disable, |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | struct meson_afbcd_ops { |
| 16 | 16 | int (*init)(struct meson_drm *priv); |
| 17 | + void (*exit)(struct meson_drm *priv); | |
| 17 | 18 | int (*reset)(struct meson_drm *priv); |
| 18 | 19 | int (*enable)(struct meson_drm *priv); |
| 19 | 20 | int (*disable)(struct meson_drm *priv); |
| @@ -529,7 +529,10 @@ static void mgag200_set_format_regs(struct mga_device *mdev, · 528 unmodified lines | ||
| 529 | 529 | WREG_GFX(3, 0x00); |
| 530 | 530 | WREG_GFX(4, 0x00); |
| 531 | 531 | WREG_GFX(5, 0x40); |
| 532 | − WREG_GFX(6, 0x05); | |
| 532 | + /* GCTL6 should be 0x05, but we configure memmapsl to 0xb8000 (text mode), | |
| 533 | + * so that it doesn't hang when running kexec/kdump on G200_SE rev42. | |
| 534 | + */ | |
| 535 | + WREG_GFX(6, 0x0d); | |
| 533 | 536 | WREG_GFX(7, 0x0f); |
| 534 | 537 | WREG_GFX(8, 0x0f); |
| 535 | 538 | |
| @@ -12,6 +12,7 @@ config DRM_MSM · 11 unmodified lines | ||
| 12 | 12 | select IOMMU_IO_PGTABLE |
| 13 | 13 | select QCOM_MDT_LOADER if ARCH_QCOM |
| 14 | 14 | select REGULATOR |
| 15 | + select DRM_DP_HELPER | |
| 15 | 16 | select DRM_KMS_HELPER |
| 16 | 17 | select DRM_PANEL |
| 17 | 18 | select DRM_BRIDGE |
| @@ -8,7 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | #include <linux/of_platform.h> |
| 10 | 10 | |
| 11 | −#include <drm/drm_dp_helper.h> | |
| 11 | +#include <drm/dp/drm_dp_helper.h> | |
| 12 | 12 | #include <drm/drm_edid.h> |
| 13 | 13 | |
| 14 | 14 | #include "dp_catalog.h" |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | #define _DP_AUX_H_ |
| 8 | 8 | |
| 9 | 9 | #include "dp_catalog.h" |
| 10 | −#include <drm/drm_dp_helper.h> | |
| 10 | +#include <drm/dp/drm_dp_helper.h> | |
| 11 | 11 | |
| 12 | 12 | int dp_aux_register(struct drm_dp_aux *dp_aux); |
| 13 | 13 | void dp_aux_unregister(struct drm_dp_aux *dp_aux); |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/phy/phy.h> |
| 11 | 11 | #include <linux/phy/phy-dp.h> |
| 12 | 12 | #include <linux/rational.h> |
| 13 | −#include <drm/drm_dp_helper.h> | |
| 13 | +#include <drm/dp/drm_dp_helper.h> | |
| 14 | 14 | #include <drm/drm_print.h> |
| 15 | 15 | |
| 16 | 16 | #include "dp_catalog.h" |
| @@ -12,7 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <linux/phy/phy-dp.h> |
| 13 | 13 | #include <linux/pm_opp.h> |
| 14 | 14 | #include <drm/drm_fixed.h> |
| 15 | −#include <drm/drm_dp_helper.h> | |
| 15 | +#include <drm/dp/drm_dp_helper.h> | |
| 16 | 16 | #include <drm/drm_print.h> |
| 17 | 17 | |
| 18 | 18 | #include "dp_reg.h" |
| @@ -0,0 +1,77 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#ifndef __EDP_CONNECTOR_H__ | |
| 7 | +#define __EDP_CONNECTOR_H__ | |
| 8 | + | |
| 9 | +#include <linux/i2c.h> | |
| 10 | +#include <linux/interrupt.h> | |
| 11 | +#include <linux/kernel.h> | |
| 12 | +#include <linux/platform_device.h> | |
| 13 | +#include <drm/dp/drm_dp_helper.h> | |
| 14 | +#include <drm/drm_bridge.h> | |
| 15 | +#include <drm/drm_crtc.h> | |
| 16 | + | |
| 17 | +#include "msm_drv.h" | |
| 18 | + | |
| 19 | +#define edp_read(offset) msm_readl((offset)) | |
| 20 | +#define edp_write(offset, data) msm_writel((data), (offset)) | |
| 21 | + | |
| 22 | +struct edp_ctrl; | |
| 23 | +struct edp_aux; | |
| 24 | +struct edp_phy; | |
| 25 | + | |
| 26 | +struct msm_edp { | |
| 27 | + struct drm_device *dev; | |
| 28 | + struct platform_device *pdev; | |
| 29 | + | |
| 30 | + struct drm_connector *connector; | |
| 31 | + struct drm_bridge *bridge; | |
| 32 | + | |
| 33 | + /* the encoder we are hooked to (outside of eDP block) */ | |
| 34 | + struct drm_encoder *encoder; | |
| 35 | + | |
| 36 | + struct edp_ctrl *ctrl; | |
| 37 | + | |
| 38 | + int irq; | |
| 39 | +}; | |
| 40 | + | |
| 41 | +/* eDP bridge */ | |
| 42 | +struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp); | |
| 43 | +void edp_bridge_destroy(struct drm_bridge *bridge); | |
| 44 | + | |
| 45 | +/* eDP connector */ | |
| 46 | +struct drm_connector *msm_edp_connector_init(struct msm_edp *edp); | |
| 47 | + | |
| 48 | +/* AUX */ | |
| 49 | +void *msm_edp_aux_init(struct msm_edp *edp, void __iomem *regbase, struct drm_dp_aux **drm_aux); | |
| 50 | +void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux); | |
| 51 | +irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr); | |
| 52 | +void msm_edp_aux_ctrl(struct edp_aux *aux, int enable); | |
| 53 | + | |
| 54 | +/* Phy */ | |
| 55 | +bool msm_edp_phy_ready(struct edp_phy *phy); | |
| 56 | +void msm_edp_phy_ctrl(struct edp_phy *phy, int enable); | |
| 57 | +void msm_edp_phy_vm_pe_init(struct edp_phy *phy); | |
| 58 | +void msm_edp_phy_vm_pe_cfg(struct edp_phy *phy, u32 v0, u32 v1); | |
| 59 | +void msm_edp_phy_lane_power_ctrl(struct edp_phy *phy, bool up, u32 max_lane); | |
| 60 | +void *msm_edp_phy_init(struct device *dev, void __iomem *regbase); | |
| 61 | + | |
| 62 | +/* Ctrl */ | |
| 63 | +irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl); | |
| 64 | +void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on); | |
| 65 | +int msm_edp_ctrl_init(struct msm_edp *edp); | |
| 66 | +void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl); | |
| 67 | +bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl); | |
| 68 | +int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, | |
| 69 | + struct drm_connector *connector, struct edid **edid); | |
| 70 | +int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl, | |
| 71 | + const struct drm_display_mode *mode, | |
| 72 | + const struct drm_display_info *info); | |
| 73 | +/* @pixel_rate is in kHz */ | |
| 74 | +bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl, | |
| 75 | + u32 pixel_rate, u32 *pm, u32 *pn); | |
| 76 | + | |
| 77 | +#endif /* __EDP_CONNECTOR_H__ */ | |
| @@ -0,0 +1,1373 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +/* | |
| 3 | + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#include <linux/clk.h> | |
| 7 | +#include <linux/gpio/consumer.h> | |
| 8 | +#include <linux/regulator/consumer.h> | |
| 9 | +#include <drm/dp/drm_dp_helper.h> | |
| 10 | +#include <drm/drm_crtc.h> | |
| 11 | +#include <drm/drm_edid.h> | |
| 12 | + | |
| 13 | +#include "edp.h" | |
| 14 | +#include "edp.xml.h" | |
| 15 | + | |
| 16 | +#define VDDA_UA_ON_LOAD 100000 /* uA units */ | |
| 17 | +#define VDDA_UA_OFF_LOAD 100 /* uA units */ | |
| 18 | + | |
| 19 | +#define DPCD_LINK_VOLTAGE_MAX 4 | |
| 20 | +#define DPCD_LINK_PRE_EMPHASIS_MAX 4 | |
| 21 | + | |
| 22 | +#define EDP_LINK_BW_MAX DP_LINK_BW_2_7 | |
| 23 | + | |
| 24 | +/* Link training return value */ | |
| 25 | +#define EDP_TRAIN_FAIL -1 | |
| 26 | +#define EDP_TRAIN_SUCCESS 0 | |
| 27 | +#define EDP_TRAIN_RECONFIG 1 | |
| 28 | + | |
| 29 | +#define EDP_CLK_MASK_AHB BIT(0) | |
| 30 | +#define EDP_CLK_MASK_AUX BIT(1) | |
| 31 | +#define EDP_CLK_MASK_LINK BIT(2) | |
| 32 | +#define EDP_CLK_MASK_PIXEL BIT(3) | |
| 33 | +#define EDP_CLK_MASK_MDP_CORE BIT(4) | |
| 34 | +#define EDP_CLK_MASK_LINK_CHAN (EDP_CLK_MASK_LINK | EDP_CLK_MASK_PIXEL) | |
| 35 | +#define EDP_CLK_MASK_AUX_CHAN \ | |
| 36 | + (EDP_CLK_MASK_AHB | EDP_CLK_MASK_AUX | EDP_CLK_MASK_MDP_CORE) | |
| 37 | +#define EDP_CLK_MASK_ALL (EDP_CLK_MASK_AUX_CHAN | EDP_CLK_MASK_LINK_CHAN) | |
| 38 | + | |
| 39 | +#define EDP_BACKLIGHT_MAX 255 | |
| 40 | + | |
| 41 | +#define EDP_INTR_STATUS1 \ | |
| 42 | + (EDP_INTERRUPT_REG_1_HPD | EDP_INTERRUPT_REG_1_AUX_I2C_DONE | \ | |
| 43 | + EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \ | |
| 44 | + EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \ | |
| 45 | + EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER | \ | |
| 46 | + EDP_INTERRUPT_REG_1_PLL_UNLOCK | EDP_INTERRUPT_REG_1_AUX_ERROR) | |
| 47 | +#define EDP_INTR_MASK1 (EDP_INTR_STATUS1 << 2) | |
| 48 | +#define EDP_INTR_STATUS2 \ | |
| 49 | + (EDP_INTERRUPT_REG_2_READY_FOR_VIDEO | \ | |
| 50 | + EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT | \ | |
| 51 | + EDP_INTERRUPT_REG_2_FRAME_END | EDP_INTERRUPT_REG_2_CRC_UPDATED) | |
| 52 | +#define EDP_INTR_MASK2 (EDP_INTR_STATUS2 << 2) | |
| 53 | + | |
| 54 | +struct edp_ctrl { | |
| 55 | + struct platform_device *pdev; | |
| 56 | + | |
| 57 | + void __iomem *base; | |
| 58 | + | |
| 59 | + /* regulators */ | |
| 60 | + struct regulator *vdda_vreg; /* 1.8 V */ | |
| 61 | + struct regulator *lvl_vreg; | |
| 62 | + | |
| 63 | + /* clocks */ | |
| 64 | + struct clk *aux_clk; | |
| 65 | + struct clk *pixel_clk; | |
| 66 | + struct clk *ahb_clk; | |
| 67 | + struct clk *link_clk; | |
| 68 | + struct clk *mdp_core_clk; | |
| 69 | + | |
| 70 | + /* gpios */ | |
| 71 | + struct gpio_desc *panel_en_gpio; | |
| 72 | + struct gpio_desc *panel_hpd_gpio; | |
| 73 | + | |
| 74 | + /* completion and mutex */ | |
| 75 | + struct completion idle_comp; | |
| 76 | + struct mutex dev_mutex; /* To protect device power status */ | |
| 77 | + | |
| 78 | + /* work queue */ | |
| 79 | + struct work_struct on_work; | |
| 80 | + struct work_struct off_work; | |
| 81 | + struct workqueue_struct *workqueue; | |
| 82 | + | |
| 83 | + /* Interrupt register lock */ | |
| 84 | + spinlock_t irq_lock; | |
| 85 | + | |
| 86 | + bool edp_connected; | |
| 87 | + bool power_on; | |
| 88 | + | |
| 89 | + /* edid raw data */ | |
| 90 | + struct edid *edid; | |
| 91 | + | |
| 92 | + struct drm_dp_aux *drm_aux; | |
| 93 | + | |
| 94 | + /* dpcd raw data */ | |
| 95 | + u8 dpcd[DP_RECEIVER_CAP_SIZE]; | |
| 96 | + | |
| 97 | + /* Link status */ | |
| 98 | + u8 link_rate; | |
| 99 | + u8 lane_cnt; | |
| 100 | + u8 v_level; | |
| 101 | + u8 p_level; | |
| 102 | + | |
| 103 | + /* Timing status */ | |
| 104 | + u8 interlaced; | |
| 105 | + u32 pixel_rate; /* in kHz */ | |
| 106 | + u32 color_depth; | |
| 107 | + | |
| 108 | + struct edp_aux *aux; | |
| 109 | + struct edp_phy *phy; | |
| 110 | +}; | |
| 111 | + | |
| 112 | +struct edp_pixel_clk_div { | |
| 113 | + u32 rate; /* in kHz */ | |
| 114 | + u32 m; | |
| 115 | + u32 n; | |
| 116 | +}; | |
| 117 | + | |
| 118 | +#define EDP_PIXEL_CLK_NUM 8 | |
| 119 | +static const struct edp_pixel_clk_div clk_divs[2][EDP_PIXEL_CLK_NUM] = { | |
| 120 | + { /* Link clock = 162MHz, source clock = 810MHz */ | |
| 121 | + {119000, 31, 211}, /* WSXGA+ 1680x1050@60Hz CVT */ | |
| 122 | + {130250, 32, 199}, /* UXGA 1600x1200@60Hz CVT */ | |
| 123 | + {148500, 11, 60}, /* FHD 1920x1080@60Hz */ | |
| 124 | + {154000, 50, 263}, /* WUXGA 1920x1200@60Hz CVT */ | |
| 125 | + {209250, 31, 120}, /* QXGA 2048x1536@60Hz CVT */ | |
| 126 | + {268500, 119, 359}, /* WQXGA 2560x1600@60Hz CVT */ | |
| 127 | + {138530, 33, 193}, /* AUO B116HAN03.0 Panel */ | |
| 128 | + {141400, 48, 275}, /* AUO B133HTN01.2 Panel */ | |
| 129 | + }, | |
| 130 | + { /* Link clock = 270MHz, source clock = 675MHz */ | |
| 131 | + {119000, 52, 295}, /* WSXGA+ 1680x1050@60Hz CVT */ | |
| 132 | + {130250, 11, 57}, /* UXGA 1600x1200@60Hz CVT */ | |
| 133 | + {148500, 11, 50}, /* FHD 1920x1080@60Hz */ | |
| 134 | + {154000, 47, 206}, /* WUXGA 1920x1200@60Hz CVT */ | |
| 135 | + {209250, 31, 100}, /* QXGA 2048x1536@60Hz CVT */ | |
| 136 | + {268500, 107, 269}, /* WQXGA 2560x1600@60Hz CVT */ | |
| 137 | + {138530, 63, 307}, /* AUO B116HAN03.0 Panel */ | |
| 138 | + {141400, 53, 253}, /* AUO B133HTN01.2 Panel */ | |
| 139 | + }, | |
| 140 | +}; | |
| 141 | + | |
| 142 | +static int edp_clk_init(struct edp_ctrl *ctrl) | |
| 143 | +{ | |
| 144 | + struct platform_device *pdev = ctrl->pdev; | |
| 145 | + int ret; | |
| 146 | + | |
| 147 | + ctrl->aux_clk = msm_clk_get(pdev, "core"); | |
| 148 | + if (IS_ERR(ctrl->aux_clk)) { | |
| 149 | + ret = PTR_ERR(ctrl->aux_clk); | |
| 150 | + pr_err("%s: Can't find core clock, %d\n", __func__, ret); | |
| 151 | + ctrl->aux_clk = NULL; | |
| 152 | + return ret; | |
| 153 | + } | |
| 154 | + | |
| 155 | + ctrl->pixel_clk = msm_clk_get(pdev, "pixel"); | |
| 156 | + if (IS_ERR(ctrl->pixel_clk)) { | |
| 157 | + ret = PTR_ERR(ctrl->pixel_clk); | |
| 158 | + pr_err("%s: Can't find pixel clock, %d\n", __func__, ret); | |
| 159 | + ctrl->pixel_clk = NULL; | |
| 160 | + return ret; | |
| 161 | + } | |
| 162 | + | |
| 163 | + ctrl->ahb_clk = msm_clk_get(pdev, "iface"); | |
| 164 | + if (IS_ERR(ctrl->ahb_clk)) { | |
| 165 | + ret = PTR_ERR(ctrl->ahb_clk); | |
| 166 | + pr_err("%s: Can't find iface clock, %d\n", __func__, ret); | |
| 167 | + ctrl->ahb_clk = NULL; | |
| 168 | + return ret; | |
| 169 | + } | |
| 170 | + | |
| 171 | + ctrl->link_clk = msm_clk_get(pdev, "link"); | |
| 172 | + if (IS_ERR(ctrl->link_clk)) { | |
| 173 | + ret = PTR_ERR(ctrl->link_clk); | |
| 174 | + pr_err("%s: Can't find link clock, %d\n", __func__, ret); | |
| 175 | + ctrl->link_clk = NULL; | |
| 176 | + return ret; | |
| 177 | + } | |
| 178 | + | |
| 179 | + /* need mdp core clock to receive irq */ | |
| 180 | + ctrl->mdp_core_clk = msm_clk_get(pdev, "mdp_core"); | |
| 181 | + if (IS_ERR(ctrl->mdp_core_clk)) { | |
| 182 | + ret = PTR_ERR(ctrl->mdp_core_clk); | |
| 183 | + pr_err("%s: Can't find mdp_core clock, %d\n", __func__, ret); | |
| 184 | + ctrl->mdp_core_clk = NULL; | |
| 185 | + return ret; | |
| 186 | + } | |
| 187 | + | |
| 188 | + return 0; | |
| 189 | +} | |
| 190 | + | |
| 191 | +static int edp_clk_enable(struct edp_ctrl *ctrl, u32 clk_mask) | |
| 192 | +{ | |
| 193 | + int ret; | |
| 194 | + | |
| 195 | + DBG("mask=%x", clk_mask); | |
| 196 | + /* ahb_clk should be enabled first */ | |
| 197 | + if (clk_mask & EDP_CLK_MASK_AHB) { | |
| 198 | + ret = clk_prepare_enable(ctrl->ahb_clk); | |
| 199 | + if (ret) { | |
| 200 | + pr_err("%s: Failed to enable ahb clk\n", __func__); | |
| 201 | + goto f0; | |
| 202 | + } | |
| 203 | + } | |
| 204 | + if (clk_mask & EDP_CLK_MASK_AUX) { | |
| 205 | + ret = clk_set_rate(ctrl->aux_clk, 19200000); | |
| 206 | + if (ret) { | |
| 207 | + pr_err("%s: Failed to set rate aux clk\n", __func__); | |
| 208 | + goto f1; | |
| 209 | + } | |
| 210 | + ret = clk_prepare_enable(ctrl->aux_clk); | |
| 211 | + if (ret) { | |
| 212 | + pr_err("%s: Failed to enable aux clk\n", __func__); | |
| 213 | + goto f1; | |
| 214 | + } | |
| 215 | + } | |
| 216 | + /* Need to set rate and enable link_clk prior to pixel_clk */ | |
| 217 | + if (clk_mask & EDP_CLK_MASK_LINK) { | |
| 218 | + DBG("edp->link_clk, set_rate %ld", | |
| 219 | + (unsigned long)ctrl->link_rate * 27000000); | |
| 220 | + ret = clk_set_rate(ctrl->link_clk, | |
| 221 | + (unsigned long)ctrl->link_rate * 27000000); | |
| 222 | + if (ret) { | |
| 223 | + pr_err("%s: Failed to set rate to link clk\n", | |
| 224 | + __func__); | |
| 225 | + goto f2; | |
| 226 | + } | |
| 227 | + | |
| 228 | + ret = clk_prepare_enable(ctrl->link_clk); | |
| 229 | + if (ret) { | |
| 230 | + pr_err("%s: Failed to enable link clk\n", __func__); | |
| 231 | + goto f2; | |
| 232 | + } | |
| 233 | + } | |
| 234 | + if (clk_mask & EDP_CLK_MASK_PIXEL) { | |
| 235 | + DBG("edp->pixel_clk, set_rate %ld", | |
| 236 | + (unsigned long)ctrl->pixel_rate * 1000); | |
| 237 | + ret = clk_set_rate(ctrl->pixel_clk, | |
| 238 | + (unsigned long)ctrl->pixel_rate * 1000); | |
| 239 | + if (ret) { | |
| 240 | + pr_err("%s: Failed to set rate to pixel clk\n", | |
| 241 | + __func__); | |
| 242 | + goto f3; | |
| 243 | + } | |
| 244 | + | |
| 245 | + ret = clk_prepare_enable(ctrl->pixel_clk); | |
| 246 | + if (ret) { | |
| 247 | + pr_err("%s: Failed to enable pixel clk\n", __func__); | |
| 248 | + goto f3; | |
| 249 | + } | |
| 250 | + } | |
| 251 | + if (clk_mask & EDP_CLK_MASK_MDP_CORE) { | |
| 252 | + ret = clk_prepare_enable(ctrl->mdp_core_clk); | |
| 253 | + if (ret) { | |
| 254 | + pr_err("%s: Failed to enable mdp core clk\n", __func__); | |
| 255 | + goto f4; | |
| 256 | + } | |
| 257 | + } | |
| 258 | + | |
| 259 | + return 0; | |
| 260 | + | |
| 261 | +f4: | |
| 262 | + if (clk_mask & EDP_CLK_MASK_PIXEL) | |
| 263 | + clk_disable_unprepare(ctrl->pixel_clk); | |
| 264 | +f3: | |
| 265 | + if (clk_mask & EDP_CLK_MASK_LINK) | |
| 266 | + clk_disable_unprepare(ctrl->link_clk); | |
| 267 | +f2: | |
| 268 | + if (clk_mask & EDP_CLK_MASK_AUX) | |
| 269 | + clk_disable_unprepare(ctrl->aux_clk); | |
| 270 | +f1: | |
| 271 | + if (clk_mask & EDP_CLK_MASK_AHB) | |
| 272 | + clk_disable_unprepare(ctrl->ahb_clk); | |
| 273 | +f0: | |
| 274 | + return ret; | |
| 275 | +} | |
| 276 | + | |
| 277 | +static void edp_clk_disable(struct edp_ctrl *ctrl, u32 clk_mask) | |
| 278 | +{ | |
| 279 | + if (clk_mask & EDP_CLK_MASK_MDP_CORE) | |
| 280 | + clk_disable_unprepare(ctrl->mdp_core_clk); | |
| 281 | + if (clk_mask & EDP_CLK_MASK_PIXEL) | |
| 282 | + clk_disable_unprepare(ctrl->pixel_clk); | |
| 283 | + if (clk_mask & EDP_CLK_MASK_LINK) | |
| 284 | + clk_disable_unprepare(ctrl->link_clk); | |
| 285 | + if (clk_mask & EDP_CLK_MASK_AUX) | |
| 286 | + clk_disable_unprepare(ctrl->aux_clk); | |
| 287 | + if (clk_mask & EDP_CLK_MASK_AHB) | |
| 288 | + clk_disable_unprepare(ctrl->ahb_clk); | |
| 289 | +} | |
| 290 | + | |
| 291 | +static int edp_regulator_init(struct edp_ctrl *ctrl) | |
| 292 | +{ | |
| 293 | + struct device *dev = &ctrl->pdev->dev; | |
| 294 | + int ret; | |
| 295 | + | |
| 296 | + DBG(""); | |
| 297 | + ctrl->vdda_vreg = devm_regulator_get(dev, "vdda"); | |
| 298 | + ret = PTR_ERR_OR_ZERO(ctrl->vdda_vreg); | |
| 299 | + if (ret) { | |
| 300 | + pr_err("%s: Could not get vdda reg, ret = %d\n", __func__, | |
| 301 | + ret); | |
| 302 | + ctrl->vdda_vreg = NULL; | |
| 303 | + return ret; | |
| 304 | + } | |
| 305 | + ctrl->lvl_vreg = devm_regulator_get(dev, "lvl-vdd"); | |
| 306 | + ret = PTR_ERR_OR_ZERO(ctrl->lvl_vreg); | |
| 307 | + if (ret) { | |
| 308 | + pr_err("%s: Could not get lvl-vdd reg, ret = %d\n", __func__, | |
| 309 | + ret); | |
| 310 | + ctrl->lvl_vreg = NULL; | |
| 311 | + return ret; | |
| 312 | + } | |
| 313 | + | |
| 314 | + return 0; | |
| 315 | +} | |
| 316 | + | |
| 317 | +static int edp_regulator_enable(struct edp_ctrl *ctrl) | |
| 318 | +{ | |
| 319 | + int ret; | |
| 320 | + | |
| 321 | + ret = regulator_set_load(ctrl->vdda_vreg, VDDA_UA_ON_LOAD); | |
| 322 | + if (ret < 0) { | |
| 323 | + pr_err("%s: vdda_vreg set regulator mode failed.\n", __func__); | |
| 324 | + goto vdda_set_fail; | |
| 325 | + } | |
| 326 | + | |
| 327 | + ret = regulator_enable(ctrl->vdda_vreg); | |
| 328 | + if (ret) { | |
| 329 | + pr_err("%s: Failed to enable vdda_vreg regulator.\n", __func__); | |
| 330 | + goto vdda_enable_fail; | |
| 331 | + } | |
| 332 | + | |
| 333 | + ret = regulator_enable(ctrl->lvl_vreg); | |
| 334 | + if (ret) { | |
| 335 | + pr_err("Failed to enable lvl-vdd reg regulator, %d", ret); | |
| 336 | + goto lvl_enable_fail; | |
| 337 | + } | |
| 338 | + | |
| 339 | + DBG("exit"); | |
| 340 | + return 0; | |
| 341 | + | |
| 342 | +lvl_enable_fail: | |
| 343 | + regulator_disable(ctrl->vdda_vreg); | |
| 344 | +vdda_enable_fail: | |
| 345 | + regulator_set_load(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD); | |
| 346 | +vdda_set_fail: | |
| 347 | + return ret; | |
| 348 | +} | |
| 349 | + | |
| 350 | +static void edp_regulator_disable(struct edp_ctrl *ctrl) | |
| 351 | +{ | |
| 352 | + regulator_disable(ctrl->lvl_vreg); | |
| 353 | + regulator_disable(ctrl->vdda_vreg); | |
| 354 | + regulator_set_load(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD); | |
| 355 | +} | |
| 356 | + | |
| 357 | +static int edp_gpio_config(struct edp_ctrl *ctrl) | |
| 358 | +{ | |
| 359 | + struct device *dev = &ctrl->pdev->dev; | |
| 360 | + int ret; | |
| 361 | + | |
| 362 | + ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd", GPIOD_IN); | |
| 363 | + if (IS_ERR(ctrl->panel_hpd_gpio)) { | |
| 364 | + ret = PTR_ERR(ctrl->panel_hpd_gpio); | |
| 365 | + ctrl->panel_hpd_gpio = NULL; | |
| 366 | + pr_err("%s: cannot get panel-hpd-gpios, %d\n", __func__, ret); | |
| 367 | + return ret; | |
| 368 | + } | |
| 369 | + | |
| 370 | + ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en", GPIOD_OUT_LOW); | |
| 371 | + if (IS_ERR(ctrl->panel_en_gpio)) { | |
| 372 | + ret = PTR_ERR(ctrl->panel_en_gpio); | |
| 373 | + ctrl->panel_en_gpio = NULL; | |
| 374 | + pr_err("%s: cannot get panel-en-gpios, %d\n", __func__, ret); | |
| 375 | + return ret; | |
| 376 | + } | |
| 377 | + | |
| 378 | + DBG("gpio on"); | |
| 379 | + | |
| 380 | + return 0; | |
| 381 | +} | |
| 382 | + | |
| 383 | +static void edp_ctrl_irq_enable(struct edp_ctrl *ctrl, int enable) | |
| 384 | +{ | |
| 385 | + unsigned long flags; | |
| 386 | + | |
| 387 | + DBG("%d", enable); | |
| 388 | + spin_lock_irqsave(&ctrl->irq_lock, flags); | |
| 389 | + if (enable) { | |
| 390 | + edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, EDP_INTR_MASK1); | |
| 391 | + edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, EDP_INTR_MASK2); | |
| 392 | + } else { | |
| 393 | + edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, 0x0); | |
| 394 | + edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, 0x0); | |
| 395 | + } | |
| 396 | + spin_unlock_irqrestore(&ctrl->irq_lock, flags); | |
| 397 | + DBG("exit"); | |
| 398 | +} | |
| 399 | + | |
| 400 | +static void edp_fill_link_cfg(struct edp_ctrl *ctrl) | |
| 401 | +{ | |
| 402 | + u32 prate; | |
| 403 | + u32 lrate; | |
| 404 | + u32 bpp; | |
| 405 | + u8 max_lane = drm_dp_max_lane_count(ctrl->dpcd); | |
| 406 | + u8 lane; | |
| 407 | + | |
| 408 | + prate = ctrl->pixel_rate; | |
| 409 | + bpp = ctrl->color_depth * 3; | |
| 410 | + | |
| 411 | + /* | |
| 412 | + * By default, use the maximum link rate and minimum lane count, | |
| 413 | + * so that we can do rate down shift during link training. | |
| 414 | + */ | |
| 415 | + ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE]; | |
| 416 | + | |
| 417 | + prate *= bpp; | |
| 418 | + prate /= 8; /* in kByte */ | |
| 419 | + | |
| 420 | + lrate = 270000; /* in kHz */ | |
| 421 | + lrate *= ctrl->link_rate; | |
| 422 | + lrate /= 10; /* in kByte, 10 bits --> 8 bits */ | |
| 423 | + | |
| 424 | + for (lane = 1; lane <= max_lane; lane <<= 1) { | |
| 425 | + if (lrate >= prate) | |
| 426 | + break; | |
| 427 | + lrate <<= 1; | |
| 428 | + } | |
| 429 | + | |
| 430 | + ctrl->lane_cnt = lane; | |
| 431 | + DBG("rate=%d lane=%d", ctrl->link_rate, ctrl->lane_cnt); | |
| 432 | +} | |
| 433 | + | |
| 434 | +static void edp_config_ctrl(struct edp_ctrl *ctrl) | |
| 435 | +{ | |
| 436 | + u32 data; | |
| 437 | + enum edp_color_depth depth; | |
| 438 | + | |
| 439 | + data = EDP_CONFIGURATION_CTRL_LANES(ctrl->lane_cnt - 1); | |
| 440 | + | |
| 441 | + if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) | |
| 442 | + data |= EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING; | |
| 443 | + | |
| 444 | + depth = EDP_6BIT; | |
| 445 | + if (ctrl->color_depth == 8) | |
| 446 | + depth = EDP_8BIT; | |
| 447 | + | |
| 448 | + data |= EDP_CONFIGURATION_CTRL_COLOR(depth); | |
| 449 | + | |
| 450 | + if (!ctrl->interlaced) /* progressive */ | |
| 451 | + data |= EDP_CONFIGURATION_CTRL_PROGRESSIVE; | |
| 452 | + | |
| 453 | + data |= (EDP_CONFIGURATION_CTRL_SYNC_CLK | | |
| 454 | + EDP_CONFIGURATION_CTRL_STATIC_MVID); | |
| 455 | + | |
| 456 | + edp_write(ctrl->base + REG_EDP_CONFIGURATION_CTRL, data); | |
| 457 | +} | |
| 458 | + | |
| 459 | +static void edp_state_ctrl(struct edp_ctrl *ctrl, u32 state) | |
| 460 | +{ | |
| 461 | + edp_write(ctrl->base + REG_EDP_STATE_CTRL, state); | |
| 462 | + /* Make sure H/W status is set */ | |
| 463 | + wmb(); | |
| 464 | +} | |
| 465 | + | |
| 466 | +static int edp_lane_set_write(struct edp_ctrl *ctrl, | |
| 467 | + u8 voltage_level, u8 pre_emphasis_level) | |
| 468 | +{ | |
| 469 | + int i; | |
| 470 | + u8 buf[4]; | |
| 471 | + | |
| 472 | + if (voltage_level >= DPCD_LINK_VOLTAGE_MAX) | |
| 473 | + voltage_level |= 0x04; | |
| 474 | + | |
| 475 | + if (pre_emphasis_level >= DPCD_LINK_PRE_EMPHASIS_MAX) | |
| 476 | + pre_emphasis_level |= 0x04; | |
| 477 | + | |
| 478 | + pre_emphasis_level <<= 3; | |
| 479 | + | |
| 480 | + for (i = 0; i < 4; i++) | |
| 481 | + buf[i] = voltage_level | pre_emphasis_level; | |
| 482 | + | |
| 483 | + DBG("%s: p|v=0x%x", __func__, voltage_level | pre_emphasis_level); | |
| 484 | + if (drm_dp_dpcd_write(ctrl->drm_aux, 0x103, buf, 4) < 4) { | |
| 485 | + pr_err("%s: Set sw/pe to panel failed\n", __func__); | |
| 486 | + return -ENOLINK; | |
| 487 | + } | |
| 488 | + | |
| 489 | + return 0; | |
| 490 | +} | |
| 491 | + | |
| 492 | +static int edp_train_pattern_set_write(struct edp_ctrl *ctrl, u8 pattern) | |
| 493 | +{ | |
| 494 | + u8 p = pattern; | |
| 495 | + | |
| 496 | + DBG("pattern=%x", p); | |
| 497 | + if (drm_dp_dpcd_write(ctrl->drm_aux, | |
| 498 | + DP_TRAINING_PATTERN_SET, &p, 1) < 1) { | |
| 499 | + pr_err("%s: Set training pattern to panel failed\n", __func__); | |
| 500 | + return -ENOLINK; | |
| 501 | + } | |
| 502 | + | |
| 503 | + return 0; | |
| 504 | +} | |
| 505 | + | |
| 506 | +static void edp_sink_train_set_adjust(struct edp_ctrl *ctrl, | |
| 507 | + const u8 *link_status) | |
| 508 | +{ | |
| 509 | + int i; | |
| 510 | + u8 max = 0; | |
| 511 | + u8 data; | |
| 512 | + | |
| 513 | + /* use the max level across lanes */ | |
| 514 | + for (i = 0; i < ctrl->lane_cnt; i++) { | |
| 515 | + data = drm_dp_get_adjust_request_voltage(link_status, i); | |
| 516 | + DBG("lane=%d req_voltage_swing=0x%x", i, data); | |
| 517 | + if (max < data) | |
| 518 | + max = data; | |
| 519 | + } | |
| 520 | + | |
| 521 | + ctrl->v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT; | |
| 522 | + | |
| 523 | + /* use the max level across lanes */ | |
| 524 | + max = 0; | |
| 525 | + for (i = 0; i < ctrl->lane_cnt; i++) { | |
| 526 | + data = drm_dp_get_adjust_request_pre_emphasis(link_status, i); | |
| 527 | + DBG("lane=%d req_pre_emphasis=0x%x", i, data); | |
| 528 | + if (max < data) | |
| 529 | + max = data; | |
| 530 | + } | |
| 531 | + | |
| 532 | + ctrl->p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT; | |
| 533 | + DBG("v_level=%d, p_level=%d", ctrl->v_level, ctrl->p_level); | |
| 534 | +} | |
| 535 | + | |
| 536 | +static void edp_host_train_set(struct edp_ctrl *ctrl, u32 train) | |
| 537 | +{ | |
| 538 | + int cnt = 10; | |
| 539 | + u32 data; | |
| 540 | + u32 shift = train - 1; | |
| 541 | + | |
| 542 | + DBG("train=%d", train); | |
| 543 | + | |
| 544 | + edp_state_ctrl(ctrl, EDP_STATE_CTRL_TRAIN_PATTERN_1 << shift); | |
| 545 | + while (--cnt) { | |
| 546 | + data = edp_read(ctrl->base + REG_EDP_MAINLINK_READY); | |
| 547 | + if (data & (EDP_MAINLINK_READY_TRAIN_PATTERN_1_READY << shift)) | |
| 548 | + break; | |
| 549 | + } | |
| 550 | + | |
| 551 | + if (cnt == 0) | |
| 552 | + pr_err("%s: set link_train=%d failed\n", __func__, train); | |
| 553 | +} | |
| 554 | + | |
| 555 | +static const u8 vm_pre_emphasis[4][4] = { | |
| 556 | + {0x03, 0x06, 0x09, 0x0C}, /* pe0, 0 db */ | |
| 557 | + {0x03, 0x06, 0x09, 0xFF}, /* pe1, 3.5 db */ | |
| 558 | + {0x03, 0x06, 0xFF, 0xFF}, /* pe2, 6.0 db */ | |
| 559 | + {0x03, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ | |
| 560 | +}; | |
| 561 | + | |
| 562 | +/* voltage swing, 0.2v and 1.0v are not support */ | |
| 563 | +static const u8 vm_voltage_swing[4][4] = { | |
| 564 | + {0x14, 0x18, 0x1A, 0x1E}, /* sw0, 0.4v */ | |
| 565 | + {0x18, 0x1A, 0x1E, 0xFF}, /* sw1, 0.6 v */ | |
| 566 | + {0x1A, 0x1E, 0xFF, 0xFF}, /* sw1, 0.8 v */ | |
| 567 | + {0x1E, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ | |
| 568 | +}; | |
| 569 | + | |
| 570 | +static int edp_voltage_pre_emphasise_set(struct edp_ctrl *ctrl) | |
| 571 | +{ | |
| 572 | + u32 value0; | |
| 573 | + u32 value1; | |
| 574 | + | |
| 575 | + DBG("v=%d p=%d", ctrl->v_level, ctrl->p_level); | |
| 576 | + | |
| 577 | + value0 = vm_pre_emphasis[(int)(ctrl->v_level)][(int)(ctrl->p_level)]; | |
| 578 | + value1 = vm_voltage_swing[(int)(ctrl->v_level)][(int)(ctrl->p_level)]; | |
| 579 | + | |
| 580 | + /* Configure host and panel only if both values are allowed */ | |
| 581 | + if (value0 != 0xFF && value1 != 0xFF) { | |
| 582 | + msm_edp_phy_vm_pe_cfg(ctrl->phy, value0, value1); | |
| 583 | + return edp_lane_set_write(ctrl, ctrl->v_level, ctrl->p_level); | |
| 584 | + } | |
| 585 | + | |
| 586 | + return -EINVAL; | |
| 587 | +} | |
| 588 | + | |
| 589 | +static int edp_start_link_train_1(struct edp_ctrl *ctrl) | |
| 590 | +{ | |
| 591 | + u8 link_status[DP_LINK_STATUS_SIZE]; | |
| 592 | + u8 old_v_level; | |
| 593 | + int tries; | |
| 594 | + int ret; | |
| 595 | + int rlen; | |
| 596 | + | |
| 597 | + DBG(""); | |
| 598 | + | |
| 599 | + edp_host_train_set(ctrl, DP_TRAINING_PATTERN_1); | |
| 600 | + ret = edp_voltage_pre_emphasise_set(ctrl); | |
| 601 | + if (ret) | |
| 602 | + return ret; | |
| 603 | + ret = edp_train_pattern_set_write(ctrl, | |
| 604 | + DP_TRAINING_PATTERN_1 | DP_RECOVERED_CLOCK_OUT_EN); | |
| 605 | + if (ret) | |
| 606 | + return ret; | |
| 607 | + | |
| 608 | + tries = 0; | |
| 609 | + old_v_level = ctrl->v_level; | |
| 610 | + while (1) { | |
| 611 | + drm_dp_link_train_clock_recovery_delay(ctrl->drm_aux, ctrl->dpcd); | |
| 612 | + | |
| 613 | + rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status); | |
| 614 | + if (rlen < DP_LINK_STATUS_SIZE) { | |
| 615 | + pr_err("%s: read link status failed\n", __func__); | |
| 616 | + return -ENOLINK; | |
| 617 | + } | |
| 618 | + if (drm_dp_clock_recovery_ok(link_status, ctrl->lane_cnt)) { | |
| 619 | + ret = 0; | |
| 620 | + break; | |
| 621 | + } | |
| 622 | + | |
| 623 | + if (ctrl->v_level == DPCD_LINK_VOLTAGE_MAX) { | |
| 624 | + ret = -1; | |
| 625 | + break; | |
| 626 | + } | |
| 627 | + | |
| 628 | + if (old_v_level == ctrl->v_level) { | |
| 629 | + tries++; | |
| 630 | + if (tries >= 5) { | |
| 631 | + ret = -1; | |
| 632 | + break; | |
| 633 | + } | |
| 634 | + } else { | |
| 635 | + tries = 0; | |
| 636 | + old_v_level = ctrl->v_level; | |
| 637 | + } | |
| 638 | + | |
| 639 | + edp_sink_train_set_adjust(ctrl, link_status); | |
| 640 | + ret = edp_voltage_pre_emphasise_set(ctrl); | |
| 641 | + if (ret) | |
| 642 | + return ret; | |
| 643 | + } | |
| 644 | + | |
| 645 | + return ret; | |
| 646 | +} | |
| 647 | + | |
| 648 | +static int edp_start_link_train_2(struct edp_ctrl *ctrl) | |
| 649 | +{ | |
| 650 | + u8 link_status[DP_LINK_STATUS_SIZE]; | |
| 651 | + int tries = 0; | |
| 652 | + int ret; | |
| 653 | + int rlen; | |
| 654 | + | |
| 655 | + DBG(""); | |
| 656 | + | |
| 657 | + edp_host_train_set(ctrl, DP_TRAINING_PATTERN_2); | |
| 658 | + ret = edp_voltage_pre_emphasise_set(ctrl); | |
| 659 | + if (ret) | |
| 660 | + return ret; | |
| 661 | + | |
| 662 | + ret = edp_train_pattern_set_write(ctrl, | |
| 663 | + DP_TRAINING_PATTERN_2 | DP_RECOVERED_CLOCK_OUT_EN); | |
| 664 | + if (ret) | |
| 665 | + return ret; | |
| 666 | + | |
| 667 | + while (1) { | |
| 668 | + drm_dp_link_train_channel_eq_delay(ctrl->drm_aux, ctrl->dpcd); | |
| 669 | + | |
| 670 | + rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status); | |
| 671 | + if (rlen < DP_LINK_STATUS_SIZE) { | |
| 672 | + pr_err("%s: read link status failed\n", __func__); | |
| 673 | + return -ENOLINK; | |
| 674 | + } | |
| 675 | + if (drm_dp_channel_eq_ok(link_status, ctrl->lane_cnt)) { | |
| 676 | + ret = 0; | |
| 677 | + break; | |
| 678 | + } | |
| 679 | + | |
| 680 | + tries++; | |
| 681 | + if (tries > 10) { | |
| 682 | + ret = -1; | |
| 683 | + break; | |
| 684 | + } | |
| 685 | + | |
| 686 | + edp_sink_train_set_adjust(ctrl, link_status); | |
| 687 | + ret = edp_voltage_pre_emphasise_set(ctrl); | |
| 688 | + if (ret) | |
| 689 | + return ret; | |
| 690 | + } | |
| 691 | + | |
| 692 | + return ret; | |
| 693 | +} | |
| 694 | + | |
| 695 | +static int edp_link_rate_down_shift(struct edp_ctrl *ctrl) | |
| 696 | +{ | |
| 697 | + u32 prate, lrate, bpp; | |
| 698 | + u8 rate, lane, max_lane; | |
| 699 | + int changed = 0; | |
| 700 | + | |
| 701 | + rate = ctrl->link_rate; | |
| 702 | + lane = ctrl->lane_cnt; | |
| 703 | + max_lane = drm_dp_max_lane_count(ctrl->dpcd); | |
| 704 | + | |
| 705 | + bpp = ctrl->color_depth * 3; | |
| 706 | + prate = ctrl->pixel_rate; | |
| 707 | + prate *= bpp; | |
| 708 | + prate /= 8; /* in kByte */ | |
| 709 | + | |
| 710 | + if (rate > DP_LINK_BW_1_62 && rate <= EDP_LINK_BW_MAX) { | |
| 711 | + rate -= 4; /* reduce rate */ | |
| 712 | + changed++; | |
| 713 | + } | |
| 714 | + | |
| 715 | + if (changed) { | |
| 716 | + if (lane >= 1 && lane < max_lane) | |
| 717 | + lane <<= 1; /* increase lane */ | |
| 718 | + | |
| 719 | + lrate = 270000; /* in kHz */ | |
| 720 | + lrate *= rate; | |
| 721 | + lrate /= 10; /* kByte, 10 bits --> 8 bits */ | |
| 722 | + lrate *= lane; | |
| 723 | + | |
| 724 | + DBG("new lrate=%u prate=%u(kHz) rate=%d lane=%d p=%u b=%d", | |
| 725 | + lrate, prate, rate, lane, | |
| 726 | + ctrl->pixel_rate, | |
| 727 | + bpp); | |
| 728 | + | |
| 729 | + if (lrate > prate) { | |
| 730 | + ctrl->link_rate = rate; | |
| 731 | + ctrl->lane_cnt = lane; | |
| 732 | + DBG("new rate=%d %d", rate, lane); | |
| 733 | + return 0; | |
| 734 | + } | |
| 735 | + } | |
| 736 | + | |
| 737 | + return -EINVAL; | |
| 738 | +} | |
| 739 | + | |
| 740 | +static int edp_clear_training_pattern(struct edp_ctrl *ctrl) | |
| 741 | +{ | |
| 742 | + int ret; | |
| 743 | + | |
| 744 | + ret = edp_train_pattern_set_write(ctrl, 0); | |
| 745 | + | |
| 746 | + drm_dp_link_train_channel_eq_delay(ctrl->drm_aux, ctrl->dpcd); | |
| 747 | + | |
| 748 | + return ret; | |
| 749 | +} | |
| 750 | + | |
| 751 | +static int edp_do_link_train(struct edp_ctrl *ctrl) | |
| 752 | +{ | |
| 753 | + u8 values[2]; | |
| 754 | + int ret; | |
| 755 | + | |
| 756 | + DBG(""); | |
| 757 | + /* | |
| 758 | + * Set the current link rate and lane cnt to panel. They may have been | |
| 759 | + * adjusted and the values are different from them in DPCD CAP | |
| 760 | + */ | |
| 761 | + values[0] = ctrl->lane_cnt; | |
| 762 | + values[1] = ctrl->link_rate; | |
| 763 | + | |
| 764 | + if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) | |
| 765 | + values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; | |
| 766 | + | |
| 767 | + if (drm_dp_dpcd_write(ctrl->drm_aux, DP_LINK_BW_SET, values, | |
| 768 | + sizeof(values)) < 0) | |
| 769 | + return EDP_TRAIN_FAIL; | |
| 770 | + | |
| 771 | + ctrl->v_level = 0; /* start from default level */ | |
| 772 | + ctrl->p_level = 0; | |
| 773 | + | |
| 774 | + edp_state_ctrl(ctrl, 0); | |
| 775 | + if (edp_clear_training_pattern(ctrl)) | |
| 776 | + return EDP_TRAIN_FAIL; | |
| 777 | + | |
| 778 | + ret = edp_start_link_train_1(ctrl); | |
| 779 | + if (ret < 0) { | |
| 780 | + if (edp_link_rate_down_shift(ctrl) == 0) { | |
| 781 | + DBG("link reconfig"); | |
| 782 | + ret = EDP_TRAIN_RECONFIG; | |
| 783 | + goto clear; | |
| 784 | + } else { | |
| 785 | + pr_err("%s: Training 1 failed", __func__); | |
| 786 | + ret = EDP_TRAIN_FAIL; | |
| 787 | + goto clear; | |
| 788 | + } | |
| 789 | + } | |
| 790 | + DBG("Training 1 completed successfully"); | |
| 791 | + | |
| 792 | + edp_state_ctrl(ctrl, 0); | |
| 793 | + if (edp_clear_training_pattern(ctrl)) | |
| 794 | + return EDP_TRAIN_FAIL; | |
| 795 | + | |
| 796 | + ret = edp_start_link_train_2(ctrl); | |
| 797 | + if (ret < 0) { | |
| 798 | + if (edp_link_rate_down_shift(ctrl) == 0) { | |
| 799 | + DBG("link reconfig"); | |
| 800 | + ret = EDP_TRAIN_RECONFIG; | |
| 801 | + goto clear; | |
| 802 | + } else { | |
| 803 | + pr_err("%s: Training 2 failed", __func__); | |
| 804 | + ret = EDP_TRAIN_FAIL; | |
| 805 | + goto clear; | |
| 806 | + } | |
| 807 | + } | |
| 808 | + DBG("Training 2 completed successfully"); | |
| 809 | + | |
| 810 | + edp_state_ctrl(ctrl, EDP_STATE_CTRL_SEND_VIDEO); | |
| 811 | +clear: | |
| 812 | + edp_clear_training_pattern(ctrl); | |
| 813 | + | |
| 814 | + return ret; | |
| 815 | +} | |
| 816 | + | |
| 817 | +static void edp_clock_synchrous(struct edp_ctrl *ctrl, int sync) | |
| 818 | +{ | |
| 819 | + u32 data; | |
| 820 | + enum edp_color_depth depth; | |
| 821 | + | |
| 822 | + data = edp_read(ctrl->base + REG_EDP_MISC1_MISC0); | |
| 823 | + | |
| 824 | + if (sync) | |
| 825 | + data |= EDP_MISC1_MISC0_SYNC; | |
| 826 | + else | |
| 827 | + data &= ~EDP_MISC1_MISC0_SYNC; | |
| 828 | + | |
| 829 | + /* only legacy rgb mode supported */ | |
| 830 | + depth = EDP_6BIT; /* Default */ | |
| 831 | + if (ctrl->color_depth == 8) | |
| 832 | + depth = EDP_8BIT; | |
| 833 | + else if (ctrl->color_depth == 10) | |
| 834 | + depth = EDP_10BIT; | |
| 835 | + else if (ctrl->color_depth == 12) | |
| 836 | + depth = EDP_12BIT; | |
| 837 | + else if (ctrl->color_depth == 16) | |
| 838 | + depth = EDP_16BIT; | |
| 839 | + | |
| 840 | + data |= EDP_MISC1_MISC0_COLOR(depth); | |
| 841 | + | |
| 842 | + edp_write(ctrl->base + REG_EDP_MISC1_MISC0, data); | |
| 843 | +} | |
| 844 | + | |
| 845 | +static int edp_sw_mvid_nvid(struct edp_ctrl *ctrl, u32 m, u32 n) | |
| 846 | +{ | |
| 847 | + u32 n_multi, m_multi = 5; | |
| 848 | + | |
| 849 | + if (ctrl->link_rate == DP_LINK_BW_1_62) { | |
| 850 | + n_multi = 1; | |
| 851 | + } else if (ctrl->link_rate == DP_LINK_BW_2_7) { | |
| 852 | + n_multi = 2; | |
| 853 | + } else { | |
| 854 | + pr_err("%s: Invalid link rate, %d\n", __func__, | |
| 855 | + ctrl->link_rate); | |
| 856 | + return -EINVAL; | |
| 857 | + } | |
| 858 | + | |
| 859 | + edp_write(ctrl->base + REG_EDP_SOFTWARE_MVID, m * m_multi); | |
| 860 | + edp_write(ctrl->base + REG_EDP_SOFTWARE_NVID, n * n_multi); | |
| 861 | + | |
| 862 | + return 0; | |
| 863 | +} | |
| 864 | + | |
| 865 | +static void edp_mainlink_ctrl(struct edp_ctrl *ctrl, int enable) | |
| 866 | +{ | |
| 867 | + u32 data = 0; | |
| 868 | + | |
| 869 | + edp_write(ctrl->base + REG_EDP_MAINLINK_CTRL, EDP_MAINLINK_CTRL_RESET); | |
| 870 | + /* Make sure fully reset */ | |
| 871 | + wmb(); | |
| 872 | + usleep_range(500, 1000); | |
| 873 | + | |
| 874 | + if (enable) | |
| 875 | + data |= EDP_MAINLINK_CTRL_ENABLE; | |
| 876 | + | |
| 877 | + edp_write(ctrl->base + REG_EDP_MAINLINK_CTRL, data); | |
| 878 | +} | |
| 879 | + | |
| 880 | +static void edp_ctrl_phy_aux_enable(struct edp_ctrl *ctrl, int enable) | |
| 881 | +{ | |
| 882 | + if (enable) { | |
| 883 | + edp_regulator_enable(ctrl); | |
| 884 | + edp_clk_enable(ctrl, EDP_CLK_MASK_AUX_CHAN); | |
| 885 | + msm_edp_phy_ctrl(ctrl->phy, 1); | |
| 886 | + msm_edp_aux_ctrl(ctrl->aux, 1); | |
| 887 | + gpiod_set_value(ctrl->panel_en_gpio, 1); | |
| 888 | + } else { | |
| 889 | + gpiod_set_value(ctrl->panel_en_gpio, 0); | |
| 890 | + msm_edp_aux_ctrl(ctrl->aux, 0); | |
| 891 | + msm_edp_phy_ctrl(ctrl->phy, 0); | |
| 892 | + edp_clk_disable(ctrl, EDP_CLK_MASK_AUX_CHAN); | |
| 893 | + edp_regulator_disable(ctrl); | |
| 894 | + } | |
| 895 | +} | |
| 896 | + | |
| 897 | +static void edp_ctrl_link_enable(struct edp_ctrl *ctrl, int enable) | |
| 898 | +{ | |
| 899 | + u32 m, n; | |
| 900 | + | |
| 901 | + if (enable) { | |
| 902 | + /* Enable link channel clocks */ | |
| 903 | + edp_clk_enable(ctrl, EDP_CLK_MASK_LINK_CHAN); | |
| 904 | + | |
| 905 | + msm_edp_phy_lane_power_ctrl(ctrl->phy, true, ctrl->lane_cnt); | |
| 906 | + | |
| 907 | + msm_edp_phy_vm_pe_init(ctrl->phy); | |
| 908 | + | |
| 909 | + /* Make sure phy is programed */ | |
| 910 | + wmb(); | |
| 911 | + msm_edp_phy_ready(ctrl->phy); | |
| 912 | + | |
| 913 | + edp_config_ctrl(ctrl); | |
| 914 | + msm_edp_ctrl_pixel_clock_valid(ctrl, ctrl->pixel_rate, &m, &n); | |
| 915 | + edp_sw_mvid_nvid(ctrl, m, n); | |
| 916 | + edp_mainlink_ctrl(ctrl, 1); | |
| 917 | + } else { | |
| 918 | + edp_mainlink_ctrl(ctrl, 0); | |
| 919 | + | |
| 920 | + msm_edp_phy_lane_power_ctrl(ctrl->phy, false, 0); | |
| 921 | + edp_clk_disable(ctrl, EDP_CLK_MASK_LINK_CHAN); | |
| 922 | + } | |
| 923 | +} | |
| 924 | + | |
| 925 | +static int edp_ctrl_training(struct edp_ctrl *ctrl) | |
| 926 | +{ | |
| 927 | + int ret; | |
| 928 | + | |
| 929 | + /* Do link training only when power is on */ | |
| 930 | + if (!ctrl->power_on) | |
| 931 | + return -EINVAL; | |
| 932 | + | |
| 933 | +train_start: | |
| 934 | + ret = edp_do_link_train(ctrl); | |
| 935 | + if (ret == EDP_TRAIN_RECONFIG) { | |
| 936 | + /* Re-configure main link */ | |
| 937 | + edp_ctrl_irq_enable(ctrl, 0); | |
| 938 | + edp_ctrl_link_enable(ctrl, 0); | |
| 939 | + msm_edp_phy_ctrl(ctrl->phy, 0); | |
| 940 | + | |
| 941 | + /* Make sure link is fully disabled */ | |
| 942 | + wmb(); | |
| 943 | + usleep_range(500, 1000); | |
| 944 | + | |
| 945 | + msm_edp_phy_ctrl(ctrl->phy, 1); | |
| 946 | + edp_ctrl_link_enable(ctrl, 1); | |
| 947 | + edp_ctrl_irq_enable(ctrl, 1); | |
| 948 | + goto train_start; | |
| 949 | + } | |
| 950 | + | |
| 951 | + return ret; | |
| 952 | +} | |
| 953 | + | |
| 954 | +static void edp_ctrl_on_worker(struct work_struct *work) | |
| 955 | +{ | |
| 956 | + struct edp_ctrl *ctrl = container_of( | |
| 957 | + work, struct edp_ctrl, on_work); | |
| 958 | + u8 value; | |
| 959 | + int ret; | |
| 960 | + | |
| 961 | + mutex_lock(&ctrl->dev_mutex); | |
| 962 | + | |
| 963 | + if (ctrl->power_on) { | |
| 964 | + DBG("already on"); | |
| 965 | + goto unlock_ret; | |
| 966 | + } | |
| 967 | + | |
| 968 | + edp_ctrl_phy_aux_enable(ctrl, 1); | |
| 969 | + edp_ctrl_link_enable(ctrl, 1); | |
| 970 | + | |
| 971 | + edp_ctrl_irq_enable(ctrl, 1); | |
| 972 | + | |
| 973 | + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ | |
| 974 | + if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { | |
| 975 | + ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); | |
| 976 | + if (ret < 0) | |
| 977 | + goto fail; | |
| 978 | + | |
| 979 | + value &= ~DP_SET_POWER_MASK; | |
| 980 | + value |= DP_SET_POWER_D0; | |
| 981 | + | |
| 982 | + ret = drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); | |
| 983 | + if (ret < 0) | |
| 984 | + goto fail; | |
| 985 | + | |
| 986 | + /* | |
| 987 | + * According to the DP 1.1 specification, a "Sink Device must | |
| 988 | + * exit the power saving state within 1 ms" (Section 2.5.3.1, | |
| 989 | + * Table 5-52, "Sink Control Field" (register 0x600). | |
| 990 | + */ | |
| 991 | + usleep_range(1000, 2000); | |
| 992 | + } | |
| 993 | + | |
| 994 | + ctrl->power_on = true; | |
| 995 | + | |
| 996 | + /* Start link training */ | |
| 997 | + ret = edp_ctrl_training(ctrl); | |
| 998 | + if (ret != EDP_TRAIN_SUCCESS) | |
| 999 | + goto fail; | |
| 1000 | + | |
| 1001 | + DBG("DONE"); | |
| 1002 | + goto unlock_ret; | |
| 1003 | + | |
| 1004 | +fail: | |
| 1005 | + edp_ctrl_irq_enable(ctrl, 0); | |
| 1006 | + edp_ctrl_link_enable(ctrl, 0); | |
| 1007 | + edp_ctrl_phy_aux_enable(ctrl, 0); | |
| 1008 | + ctrl->power_on = false; | |
| 1009 | +unlock_ret: | |
| 1010 | + mutex_unlock(&ctrl->dev_mutex); | |
| 1011 | +} | |
| 1012 | + | |
| 1013 | +static void edp_ctrl_off_worker(struct work_struct *work) | |
| 1014 | +{ | |
| 1015 | + struct edp_ctrl *ctrl = container_of( | |
| 1016 | + work, struct edp_ctrl, off_work); | |
| 1017 | + unsigned long time_left; | |
| 1018 | + | |
| 1019 | + mutex_lock(&ctrl->dev_mutex); | |
| 1020 | + | |
| 1021 | + if (!ctrl->power_on) { | |
| 1022 | + DBG("already off"); | |
| 1023 | + goto unlock_ret; | |
| 1024 | + } | |
| 1025 | + | |
| 1026 | + reinit_completion(&ctrl->idle_comp); | |
| 1027 | + edp_state_ctrl(ctrl, EDP_STATE_CTRL_PUSH_IDLE); | |
| 1028 | + | |
| 1029 | + time_left = wait_for_completion_timeout(&ctrl->idle_comp, | |
| 1030 | + msecs_to_jiffies(500)); | |
| 1031 | + if (!time_left) | |
| 1032 | + DBG("%s: idle pattern timedout\n", __func__); | |
| 1033 | + | |
| 1034 | + edp_state_ctrl(ctrl, 0); | |
| 1035 | + | |
| 1036 | + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ | |
| 1037 | + if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { | |
| 1038 | + u8 value; | |
| 1039 | + int ret; | |
| 1040 | + | |
| 1041 | + ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); | |
| 1042 | + if (ret > 0) { | |
| 1043 | + value &= ~DP_SET_POWER_MASK; | |
| 1044 | + value |= DP_SET_POWER_D3; | |
| 1045 | + | |
| 1046 | + drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); | |
| 1047 | + } | |
| 1048 | + } | |
| 1049 | + | |
| 1050 | + edp_ctrl_irq_enable(ctrl, 0); | |
| 1051 | + | |
| 1052 | + edp_ctrl_link_enable(ctrl, 0); | |
| 1053 | + | |
| 1054 | + edp_ctrl_phy_aux_enable(ctrl, 0); | |
| 1055 | + | |
| 1056 | + ctrl->power_on = false; | |
| 1057 | + | |
| 1058 | +unlock_ret: | |
| 1059 | + mutex_unlock(&ctrl->dev_mutex); | |
| 1060 | +} | |
| 1061 | + | |
| 1062 | +irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl) | |
| 1063 | +{ | |
| 1064 | + u32 isr1, isr2, mask1, mask2; | |
| 1065 | + u32 ack; | |
| 1066 | + | |
| 1067 | + DBG(""); | |
| 1068 | + spin_lock(&ctrl->irq_lock); | |
| 1069 | + isr1 = edp_read(ctrl->base + REG_EDP_INTERRUPT_REG_1); | |
| 1070 | + isr2 = edp_read(ctrl->base + REG_EDP_INTERRUPT_REG_2); | |
| 1071 | + | |
| 1072 | + mask1 = isr1 & EDP_INTR_MASK1; | |
| 1073 | + mask2 = isr2 & EDP_INTR_MASK2; | |
| 1074 | + | |
| 1075 | + isr1 &= ~mask1; /* remove masks bit */ | |
| 1076 | + isr2 &= ~mask2; | |
| 1077 | + | |
| 1078 | + DBG("isr=%x mask=%x isr2=%x mask2=%x", | |
| 1079 | + isr1, mask1, isr2, mask2); | |
| 1080 | + | |
| 1081 | + ack = isr1 & EDP_INTR_STATUS1; | |
| 1082 | + ack <<= 1; /* ack bits */ | |
| 1083 | + ack |= mask1; | |
| 1084 | + edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, ack); | |
| 1085 | + | |
| 1086 | + ack = isr2 & EDP_INTR_STATUS2; | |
| 1087 | + ack <<= 1; /* ack bits */ | |
| 1088 | + ack |= mask2; | |
| 1089 | + edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, ack); | |
| 1090 | + spin_unlock(&ctrl->irq_lock); | |
| 1091 | + | |
| 1092 | + if (isr1 & EDP_INTERRUPT_REG_1_HPD) | |
| 1093 | + DBG("edp_hpd"); | |
| 1094 | + | |
| 1095 | + if (isr2 & EDP_INTERRUPT_REG_2_READY_FOR_VIDEO) | |
| 1096 | + DBG("edp_video_ready"); | |
| 1097 | + | |
| 1098 | + if (isr2 & EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT) { | |
| 1099 | + DBG("idle_patterns_sent"); | |
| 1100 | + complete(&ctrl->idle_comp); | |
| 1101 | + } | |
| 1102 | + | |
| 1103 | + msm_edp_aux_irq(ctrl->aux, isr1); | |
| 1104 | + | |
| 1105 | + return IRQ_HANDLED; | |
| 1106 | +} | |
| 1107 | + | |
| 1108 | +void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on) | |
| 1109 | +{ | |
| 1110 | + if (on) | |
| 1111 | + queue_work(ctrl->workqueue, &ctrl->on_work); | |
| 1112 | + else | |
| 1113 | + queue_work(ctrl->workqueue, &ctrl->off_work); | |
| 1114 | +} | |
| 1115 | + | |
| 1116 | +int msm_edp_ctrl_init(struct msm_edp *edp) | |
| 1117 | +{ | |
| 1118 | + struct edp_ctrl *ctrl = NULL; | |
| 1119 | + struct device *dev; | |
| 1120 | + int ret; | |
| 1121 | + | |
| 1122 | + if (!edp) { | |
| 1123 | + pr_err("%s: edp is NULL!\n", __func__); | |
| 1124 | + return -EINVAL; | |
| 1125 | + } | |
| 1126 | + | |
| 1127 | + dev = &edp->pdev->dev; | |
| 1128 | + ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); | |
| 1129 | + if (!ctrl) | |
| 1130 | + return -ENOMEM; | |
| 1131 | + | |
| 1132 | + edp->ctrl = ctrl; | |
| 1133 | + ctrl->pdev = edp->pdev; | |
| 1134 | + | |
| 1135 | + ctrl->base = msm_ioremap(ctrl->pdev, "edp", "eDP"); | |
| 1136 | + if (IS_ERR(ctrl->base)) | |
| 1137 | + return PTR_ERR(ctrl->base); | |
| 1138 | + | |
| 1139 | + /* Get regulator, clock, gpio, pwm */ | |
| 1140 | + ret = edp_regulator_init(ctrl); | |
| 1141 | + if (ret) { | |
| 1142 | + pr_err("%s:regulator init fail\n", __func__); | |
| 1143 | + return ret; | |
| 1144 | + } | |
| 1145 | + ret = edp_clk_init(ctrl); | |
| 1146 | + if (ret) { | |
| 1147 | + pr_err("%s:clk init fail\n", __func__); | |
| 1148 | + return ret; | |
| 1149 | + } | |
| 1150 | + ret = edp_gpio_config(ctrl); | |
| 1151 | + if (ret) { | |
| 1152 | + pr_err("%s:failed to configure GPIOs: %d", __func__, ret); | |
| 1153 | + return ret; | |
| 1154 | + } | |
| 1155 | + | |
| 1156 | + /* Init aux and phy */ | |
| 1157 | + ctrl->aux = msm_edp_aux_init(edp, ctrl->base, &ctrl->drm_aux); | |
| 1158 | + if (!ctrl->aux || !ctrl->drm_aux) { | |
| 1159 | + pr_err("%s:failed to init aux\n", __func__); | |
| 1160 | + return -ENOMEM; | |
| 1161 | + } | |
| 1162 | + | |
| 1163 | + ctrl->phy = msm_edp_phy_init(dev, ctrl->base); | |
| 1164 | + if (!ctrl->phy) { | |
| 1165 | + pr_err("%s:failed to init phy\n", __func__); | |
| 1166 | + ret = -ENOMEM; | |
| 1167 | + goto err_destory_aux; | |
| 1168 | + } | |
| 1169 | + | |
| 1170 | + spin_lock_init(&ctrl->irq_lock); | |
| 1171 | + mutex_init(&ctrl->dev_mutex); | |
| 1172 | + init_completion(&ctrl->idle_comp); | |
| 1173 | + | |
| 1174 | + /* setup workqueue */ | |
| 1175 | + ctrl->workqueue = alloc_ordered_workqueue("edp_drm_work", 0); | |
| 1176 | + INIT_WORK(&ctrl->on_work, edp_ctrl_on_worker); | |
| 1177 | + INIT_WORK(&ctrl->off_work, edp_ctrl_off_worker); | |
| 1178 | + | |
| 1179 | + return 0; | |
| 1180 | + | |
| 1181 | +err_destory_aux: | |
| 1182 | + msm_edp_aux_destroy(dev, ctrl->aux); | |
| 1183 | + ctrl->aux = NULL; | |
| 1184 | + return ret; | |
| 1185 | +} | |
| 1186 | + | |
| 1187 | +void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl) | |
| 1188 | +{ | |
| 1189 | + if (!ctrl) | |
| 1190 | + return; | |
| 1191 | + | |
| 1192 | + if (ctrl->workqueue) { | |
| 1193 | + destroy_workqueue(ctrl->workqueue); | |
| 1194 | + ctrl->workqueue = NULL; | |
| 1195 | + } | |
| 1196 | + | |
| 1197 | + if (ctrl->aux) { | |
| 1198 | + msm_edp_aux_destroy(&ctrl->pdev->dev, ctrl->aux); | |
| 1199 | + ctrl->aux = NULL; | |
| 1200 | + } | |
| 1201 | + | |
| 1202 | + kfree(ctrl->edid); | |
| 1203 | + ctrl->edid = NULL; | |
| 1204 | + | |
| 1205 | + mutex_destroy(&ctrl->dev_mutex); | |
| 1206 | +} | |
| 1207 | + | |
| 1208 | +bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl) | |
| 1209 | +{ | |
| 1210 | + mutex_lock(&ctrl->dev_mutex); | |
| 1211 | + DBG("connect status = %d", ctrl->edp_connected); | |
| 1212 | + if (ctrl->edp_connected) { | |
| 1213 | + mutex_unlock(&ctrl->dev_mutex); | |
| 1214 | + return true; | |
| 1215 | + } | |
| 1216 | + | |
| 1217 | + if (!ctrl->power_on) { | |
| 1218 | + edp_ctrl_phy_aux_enable(ctrl, 1); | |
| 1219 | + edp_ctrl_irq_enable(ctrl, 1); | |
| 1220 | + } | |
| 1221 | + | |
| 1222 | + if (drm_dp_dpcd_read(ctrl->drm_aux, DP_DPCD_REV, ctrl->dpcd, | |
| 1223 | + DP_RECEIVER_CAP_SIZE) < DP_RECEIVER_CAP_SIZE) { | |
| 1224 | + pr_err("%s: AUX channel is NOT ready\n", __func__); | |
| 1225 | + memset(ctrl->dpcd, 0, DP_RECEIVER_CAP_SIZE); | |
| 1226 | + } else { | |
| 1227 | + ctrl->edp_connected = true; | |
| 1228 | + } | |
| 1229 | + | |
| 1230 | + if (!ctrl->power_on) { | |
| 1231 | + edp_ctrl_irq_enable(ctrl, 0); | |
| 1232 | + edp_ctrl_phy_aux_enable(ctrl, 0); | |
| 1233 | + } | |
| 1234 | + | |
| 1235 | + DBG("exit: connect status=%d", ctrl->edp_connected); | |
| 1236 | + | |
| 1237 | + mutex_unlock(&ctrl->dev_mutex); | |
| 1238 | + | |
| 1239 | + return ctrl->edp_connected; | |
| 1240 | +} | |
| 1241 | + | |
| 1242 | +int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, | |
| 1243 | + struct drm_connector *connector, struct edid **edid) | |
| 1244 | +{ | |
| 1245 | + mutex_lock(&ctrl->dev_mutex); | |
| 1246 | + | |
| 1247 | + if (ctrl->edid) { | |
| 1248 | + if (edid) { | |
| 1249 | + DBG("Just return edid buffer"); | |
| 1250 | + *edid = ctrl->edid; | |
| 1251 | + } | |
| 1252 | + goto unlock_ret; | |
| 1253 | + } | |
| 1254 | + | |
| 1255 | + if (!ctrl->power_on) { | |
| 1256 | + edp_ctrl_phy_aux_enable(ctrl, 1); | |
| 1257 | + edp_ctrl_irq_enable(ctrl, 1); | |
| 1258 | + } | |
| 1259 | + | |
| 1260 | + /* Initialize link rate as panel max link rate */ | |
| 1261 | + ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE]; | |
| 1262 | + | |
| 1263 | + ctrl->edid = drm_get_edid(connector, &ctrl->drm_aux->ddc); | |
| 1264 | + if (!ctrl->edid) { | |
| 1265 | + pr_err("%s: edid read fail\n", __func__); | |
| 1266 | + goto disable_ret; | |
| 1267 | + } | |
| 1268 | + | |
| 1269 | + if (edid) | |
| 1270 | + *edid = ctrl->edid; | |
| 1271 | + | |
| 1272 | +disable_ret: | |
| 1273 | + if (!ctrl->power_on) { | |
| 1274 | + edp_ctrl_irq_enable(ctrl, 0); | |
| 1275 | + edp_ctrl_phy_aux_enable(ctrl, 0); | |
| 1276 | + } | |
| 1277 | +unlock_ret: | |
| 1278 | + mutex_unlock(&ctrl->dev_mutex); | |
| 1279 | + return 0; | |
| 1280 | +} | |
| 1281 | + | |
| 1282 | +int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl, | |
| 1283 | + const struct drm_display_mode *mode, | |
| 1284 | + const struct drm_display_info *info) | |
| 1285 | +{ | |
| 1286 | + u32 hstart_from_sync, vstart_from_sync; | |
| 1287 | + u32 data; | |
| 1288 | + int ret = 0; | |
| 1289 | + | |
| 1290 | + mutex_lock(&ctrl->dev_mutex); | |
| 1291 | + /* | |
| 1292 | + * Need to keep color depth, pixel rate and | |
| 1293 | + * interlaced information in ctrl context | |
| 1294 | + */ | |
| 1295 | + ctrl->color_depth = info->bpc; | |
| 1296 | + ctrl->pixel_rate = mode->clock; | |
| 1297 | + ctrl->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); | |
| 1298 | + | |
| 1299 | + /* Fill initial link config based on passed in timing */ | |
| 1300 | + edp_fill_link_cfg(ctrl); | |
| 1301 | + | |
| 1302 | + if (edp_clk_enable(ctrl, EDP_CLK_MASK_AHB)) { | |
| 1303 | + pr_err("%s, fail to prepare enable ahb clk\n", __func__); | |
| 1304 | + ret = -EINVAL; | |
| 1305 | + goto unlock_ret; | |
| 1306 | + } | |
| 1307 | + edp_clock_synchrous(ctrl, 1); | |
| 1308 | + | |
| 1309 | + /* Configure eDP timing to HW */ | |
| 1310 | + edp_write(ctrl->base + REG_EDP_TOTAL_HOR_VER, | |
| 1311 | + EDP_TOTAL_HOR_VER_HORIZ(mode->htotal) | | |
| 1312 | + EDP_TOTAL_HOR_VER_VERT(mode->vtotal)); | |
| 1313 | + | |
| 1314 | + vstart_from_sync = mode->vtotal - mode->vsync_start; | |
| 1315 | + hstart_from_sync = mode->htotal - mode->hsync_start; | |
| 1316 | + edp_write(ctrl->base + REG_EDP_START_HOR_VER_FROM_SYNC, | |
| 1317 | + EDP_START_HOR_VER_FROM_SYNC_HORIZ(hstart_from_sync) | | |
| 1318 | + EDP_START_HOR_VER_FROM_SYNC_VERT(vstart_from_sync)); | |
| 1319 | + | |
| 1320 | + data = EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT( | |
| 1321 | + mode->vsync_end - mode->vsync_start); | |
| 1322 | + data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ( | |
| 1323 | + mode->hsync_end - mode->hsync_start); | |
| 1324 | + if (mode->flags & DRM_MODE_FLAG_NVSYNC) | |
| 1325 | + data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_NVSYNC; | |
| 1326 | + if (mode->flags & DRM_MODE_FLAG_NHSYNC) | |
| 1327 | + data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_NHSYNC; | |
| 1328 | + edp_write(ctrl->base + REG_EDP_HSYNC_VSYNC_WIDTH_POLARITY, data); | |
| 1329 | + | |
| 1330 | + edp_write(ctrl->base + REG_EDP_ACTIVE_HOR_VER, | |
| 1331 | + EDP_ACTIVE_HOR_VER_HORIZ(mode->hdisplay) | | |
| 1332 | + EDP_ACTIVE_HOR_VER_VERT(mode->vdisplay)); | |
| 1333 | + | |
| 1334 | + edp_clk_disable(ctrl, EDP_CLK_MASK_AHB); | |
| 1335 | + | |
| 1336 | +unlock_ret: | |
| 1337 | + mutex_unlock(&ctrl->dev_mutex); | |
| 1338 | + return ret; | |
| 1339 | +} | |
| 1340 | + | |
| 1341 | +bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl, | |
| 1342 | + u32 pixel_rate, u32 *pm, u32 *pn) | |
| 1343 | +{ | |
| 1344 | + const struct edp_pixel_clk_div *divs; | |
| 1345 | + u32 err = 1; /* 1% error tolerance */ | |
| 1346 | + u32 clk_err; | |
| 1347 | + int i; | |
| 1348 | + | |
| 1349 | + if (ctrl->link_rate == DP_LINK_BW_1_62) { | |
| 1350 | + divs = clk_divs[0]; | |
| 1351 | + } else if (ctrl->link_rate == DP_LINK_BW_2_7) { | |
| 1352 | + divs = clk_divs[1]; | |
| 1353 | + } else { | |
| 1354 | + pr_err("%s: Invalid link rate,%d\n", __func__, ctrl->link_rate); | |
| 1355 | + return false; | |
| 1356 | + } | |
| 1357 | + | |
| 1358 | + for (i = 0; i < EDP_PIXEL_CLK_NUM; i++) { | |
| 1359 | + clk_err = abs(divs[i].rate - pixel_rate); | |
| 1360 | + if ((divs[i].rate * err / 100) >= clk_err) { | |
| 1361 | + if (pm) | |
| 1362 | + *pm = divs[i].m; | |
| 1363 | + if (pn) | |
| 1364 | + *pn = divs[i].n; | |
| 1365 | + return true; | |
| 1366 | + } | |
| 1367 | + } | |
| 1368 | + | |
| 1369 | + DBG("pixel clock %d(kHz) not supported", pixel_rate); | |
| 1370 | + | |
| 1371 | + return false; | |
| 1372 | +} | |
| 1373 | + | |
| @@ -374,12 +374,20 @@ static int mxsfb_remove(struct platform_device *pdev) · 373 unmodified lines | ||
| 374 | 374 | struct drm_device *drm = platform_get_drvdata(pdev); |
| 375 | 375 | |
| 376 | 376 | drm_dev_unregister(drm); |
| 377 | + drm_atomic_helper_shutdown(drm); | |
| 377 | 378 | mxsfb_unload(drm); |
| 378 | 379 | drm_dev_put(drm); |
| 379 | 380 | |
| 380 | 381 | return 0; |
| 381 | 382 | } |
| 382 | 383 | |
| 384 | +static void mxsfb_shutdown(struct platform_device *pdev) | |
| 385 | +{ | |
| 386 | + struct drm_device *drm = platform_get_drvdata(pdev); | |
| 387 | + | |
| 388 | + drm_atomic_helper_shutdown(drm); | |
| 389 | +} | |
| 390 | + | |
| 383 | 391 | #ifdef CONFIG_PM_SLEEP |
| 384 | 392 | static int mxsfb_suspend(struct device *dev) |
| 385 | 393 | { |
| @@ -403,6 +411,7 @@ static const struct dev_pm_ops mxsfb_pm_ops = { · 17 unmodified lines | ||
| 403 | 411 | static struct platform_driver mxsfb_platform_driver = { |
| 404 | 412 | .probe = mxsfb_probe, |
| 405 | 413 | .remove = mxsfb_remove, |
| 414 | + .shutdown = mxsfb_shutdown, | |
| 406 | 415 | .driver = { |
| 407 | 416 | .name = "mxsfb", |
| 408 | 417 | .of_match_table = mxsfb_dt_ids, |
| @@ -4,6 +4,7 @@ config DRM_NOUVEAU · 3 unmodified lines | ||
| 4 | 4 | depends on DRM && PCI && MMU |
| 5 | 5 | select IOMMU_API |
| 6 | 6 | select FW_LOADER |
| 7 | + select DRM_DP_HELPER | |
| 7 | 8 | select DRM_KMS_HELPER |
| 8 | 9 | select DRM_TTM |
| 9 | 10 | select DRM_TTM_HELPER |
| @@ -35,7 +35,7 @@ · 34 unmodified lines | ||
| 35 | 35 | |
| 36 | 36 | #include <drm/drm_atomic.h> |
| 37 | 37 | #include <drm/drm_atomic_helper.h> |
| 38 | −#include <drm/drm_dp_helper.h> | |
| 38 | +#include <drm/dp/drm_dp_helper.h> | |
| 39 | 39 | #include <drm/drm_edid.h> |
| 40 | 40 | #include <drm/drm_fb_helper.h> |
| 41 | 41 | #include <drm/drm_plane_helper.h> |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | ||
| 36 | 36 | #include <drm/drm_crtc.h> |
| 37 | 37 | #include <drm/drm_edid.h> |
| 38 | 38 | #include <drm/drm_encoder.h> |
| 39 | −#include <drm/drm_dp_helper.h> | |
| 39 | +#include <drm/dp/drm_dp_helper.h> | |
| 40 | 40 | #include <drm/drm_util.h> |
| 41 | 41 | |
| 42 | 42 | #include "nouveau_crtc.h" |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | * Authors: Ben Skeggs |
| 23 | 23 | */ |
| 24 | 24 | |
| 25 | −#include <drm/drm_dp_helper.h> | |
| 25 | +#include <drm/dp/drm_dp_helper.h> | |
| 26 | 26 | |
| 27 | 27 | #include "nouveau_drv.h" |
| 28 | 28 | #include "nouveau_connector.h" |
| @@ -147,6 +147,21 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, · 118 unmodified lines | ||
| 147 | 147 | nv_encoder->dp.link_nr = |
| 148 | 148 | dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; |
| 149 | 149 | |
| 150 | + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && dpcd[DP_DPCD_REV] >= 0x13) { | |
| 151 | + struct drm_dp_aux *aux = &nv_connector->aux; | |
| 152 | + int ret, i; | |
| 153 | + u8 sink_rates[16]; | |
| 154 | + | |
| 155 | + ret = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES, sink_rates, sizeof(sink_rates)); | |
| 156 | + if (ret == sizeof(sink_rates)) { | |
| 157 | + for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) { | |
| 158 | + int val = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10; | |
| 159 | + if (val && (i == 0 || val > nv_encoder->dp.link_bw)) | |
| 160 | + nv_encoder->dp.link_bw = val; | |
| 161 | + } | |
| 162 | + } | |
| 163 | + } | |
| 164 | + | |
| 150 | 165 | NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n", |
| 151 | 166 | nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, |
| 152 | 167 | dpcd[DP_DPCD_REV]); |
| @@ -30,8 +30,8 @@ · 29 unmodified lines | ||
| 30 | 30 | #include <subdev/bios/dcb.h> |
| 31 | 31 | |
| 32 | 32 | #include <drm/drm_encoder_slave.h> |
| 33 | −#include <drm/drm_dp_helper.h> | |
| 34 | −#include <drm/drm_dp_mst_helper.h> | |
| 33 | +#include <drm/dp/drm_dp_helper.h> | |
| 34 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 35 | 35 | #include "dispnv04/disp.h" |
| 36 | 36 | struct nv50_head_atom; |
| 37 | 37 | struct nouveau_connector; |
| @@ -162,11 +162,12 @@ nouveau_mem_vram(struct ttm_resource *reg, bool contig, u8 page) · 161 unmodified lines | ||
| 162 | 162 | } |
| 163 | 163 | |
| 164 | 164 | void |
| 165 | −nouveau_mem_del(struct ttm_resource *reg) | |
| 165 | +nouveau_mem_del(struct ttm_resource_manager *man, struct ttm_resource *reg) | |
| 166 | 166 | { |
| 167 | 167 | struct nouveau_mem *mem = nouveau_mem(reg); |
| 168 | 168 | |
| 169 | 169 | nouveau_mem_fini(mem); |
| 170 | + ttm_resource_fini(man, reg); | |
| 170 | 171 | kfree(mem); |
| 171 | 172 | } |
| 172 | 173 | |
| @@ -23,7 +23,8 @@ nouveau_mem(struct ttm_resource *reg) · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | int nouveau_mem_new(struct nouveau_cli *, u8 kind, u8 comp, |
| 25 | 25 | struct ttm_resource **); |
| 26 | −void nouveau_mem_del(struct ttm_resource *); | |
| 26 | +void nouveau_mem_del(struct ttm_resource_manager *man, | |
| 27 | + struct ttm_resource *); | |
| 27 | 28 | int nouveau_mem_vram(struct ttm_resource *, bool contig, u8 page); |
| 28 | 29 | int nouveau_mem_host(struct ttm_resource *, struct ttm_tt *); |
| 29 | 30 | void nouveau_mem_fini(struct nouveau_mem *); |
| @@ -36,9 +36,10 @@ · 35 unmodified lines | ||
| 36 | 36 | #include <core/tegra.h> |
| 37 | 37 | |
| 38 | 38 | static void |
| 39 | −nouveau_manager_del(struct ttm_resource_manager *man, struct ttm_resource *reg) | |
| 39 | +nouveau_manager_del(struct ttm_resource_manager *man, | |
| 40 | + struct ttm_resource *reg) | |
| 40 | 41 | { |
| 41 | − nouveau_mem_del(reg); | |
| 42 | + nouveau_mem_del(man, reg); | |
| 42 | 43 | } |
| 43 | 44 | |
| 44 | 45 | static int |
| @@ -62,7 +63,7 @@ nouveau_vram_manager_new(struct ttm_resource_manager *man, · 17 unmodified lines | ||
| 62 | 63 | |
| 63 | 64 | ret = nouveau_mem_vram(*res, nvbo->contig, nvbo->page); |
| 64 | 65 | if (ret) { |
| 65 | − nouveau_mem_del(*res); | |
| 66 | + nouveau_mem_del(man, *res); | |
| 66 | 67 | return ret; |
| 67 | 68 | } |
| 68 | 69 | |
| @@ -118,7 +119,7 @@ nv04_gart_manager_new(struct ttm_resource_manager *man, · 49 unmodified lines | ||
| 118 | 119 | ret = nvif_vmm_get(&mem->cli->vmm.vmm, PTES, false, 12, 0, |
| 119 | 120 | (long)(*res)->num_pages << PAGE_SHIFT, &mem->vma[0]); |
| 120 | 121 | if (ret) { |
| 121 | − nouveau_mem_del(*res); | |
| 122 | + nouveau_mem_del(man, *res); | |
| 122 | 123 | return ret; |
| 123 | 124 | } |
| 124 | 125 | |
| @@ -163,7 +164,7 @@ nouveau_ttm_init_vram(struct nouveau_drm *drm) · 38 unmodified lines | ||
| 163 | 164 | |
| 164 | 165 | man->func = &nouveau_vram_manager; |
| 165 | 166 | |
| 166 | − ttm_resource_manager_init(man, | |
| 167 | + ttm_resource_manager_init(man, &drm->ttm.bdev, | |
| 167 | 168 | drm->gem.vram_available >> PAGE_SHIFT); |
| 168 | 169 | ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man); |
| 169 | 170 | ttm_resource_manager_set_used(man, true); |
| @@ -210,7 +211,7 @@ nouveau_ttm_init_gtt(struct nouveau_drm *drm) · 40 unmodified lines | ||
| 210 | 211 | |
| 211 | 212 | man->func = func; |
| 212 | 213 | man->use_tt = true; |
| 213 | − ttm_resource_manager_init(man, size_pages); | |
| 214 | + ttm_resource_manager_init(man, &drm->ttm.bdev, size_pages); | |
| 214 | 215 | ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, man); |
| 215 | 216 | ttm_resource_manager_set_used(man, true); |
| 216 | 217 | return 0; |
| @@ -41,6 +41,10 @@ · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | struct lt_state { |
| 43 | 43 | struct nvkm_dp *dp; |
| 44 | + | |
| 45 | + int repeaters; | |
| 46 | + int repeater; | |
| 47 | + | |
| 44 | 48 | u8 stat[6]; |
| 45 | 49 | u8 conf[4]; |
| 46 | 50 | bool pc2; |
| @@ -52,14 +56,26 @@ static int · 5 unmodified lines | ||
| 52 | 56 | nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay) |
| 53 | 57 | { |
| 54 | 58 | struct nvkm_dp *dp = lt->dp; |
| 59 | + u32 addr; | |
| 55 | 60 | int ret; |
| 56 | 61 | |
| 57 | − if (dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) | |
| 58 | − mdelay(dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); | |
| 62 | + usleep_range(delay, delay * 2); | |
| 63 | + | |
| 64 | + if (lt->repeater) | |
| 65 | + addr = DPCD_LTTPR_LANE0_1_STATUS(lt->repeater); | |
| 66 | + else | |
| 67 | + addr = DPCD_LS02; | |
| 68 | + | |
| 69 | + ret = nvkm_rdaux(dp->aux, addr, <->stat[0], 3); | |
| 70 | + if (ret) | |
| 71 | + return ret; | |
| 72 | + | |
| 73 | + if (lt->repeater) | |
| 74 | + addr = DPCD_LTTPR_LANE0_1_ADJUST(lt->repeater); | |
| 59 | 75 | else |
| 60 | − udelay(delay); | |
| 76 | + addr = DPCD_LS06; | |
| 61 | 77 | |
| 62 | − ret = nvkm_rdaux(dp->aux, DPCD_LS02, lt->stat, 6); | |
| 78 | + ret = nvkm_rdaux(dp->aux, addr, <->stat[4], 2); | |
| 63 | 79 | if (ret) |
| 64 | 80 | return ret; |
| 65 | 81 | |
| @@ -85,6 +101,7 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) · 19 unmodified lines | ||
| 85 | 101 | struct nvbios_dpout info; |
| 86 | 102 | struct nvbios_dpcfg ocfg; |
| 87 | 103 | u8 ver, hdr, cnt, len; |
| 104 | + u32 addr; | |
| 88 | 105 | u32 data; |
| 89 | 106 | int ret, i; |
| 90 | 107 | |
| @@ -113,6 +130,9 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) · 22 unmodified lines | ||
| 113 | 130 | OUTP_TRACE(&dp->outp, "config lane %d %02x %02x", |
| 114 | 131 | i, lt->conf[i], lpc2); |
| 115 | 132 | |
| 133 | + if (lt->repeater != lt->repeaters) | |
| 134 | + continue; | |
| 135 | + | |
| 116 | 136 | data = nvbios_dpout_match(bios, dp->outp.info.hasht, |
| 117 | 137 | dp->outp.info.hashm, |
| 118 | 138 | &ver, &hdr, &cnt, &len, &info); |
| @@ -129,7 +149,12 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) · 10 unmodified lines | ||
| 129 | 149 | ocfg.pe, ocfg.tx_pu); |
| 130 | 150 | } |
| 131 | 151 | |
| 132 | − ret = nvkm_wraux(dp->aux, DPCD_LC03(0), lt->conf, 4); | |
| 152 | + if (lt->repeater) | |
| 153 | + addr = DPCD_LTTPR_LANE0_SET(lt->repeater); | |
| 154 | + else | |
| 155 | + addr = DPCD_LC03(0); | |
| 156 | + | |
| 157 | + ret = nvkm_wraux(dp->aux, addr, lt->conf, 4); | |
| 133 | 158 | if (ret) |
| 134 | 159 | return ret; |
| 135 | 160 | |
| @@ -146,32 +171,59 @@ static void · 10 unmodified lines | ||
| 146 | 171 | nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern) |
| 147 | 172 | { |
| 148 | 173 | struct nvkm_dp *dp = lt->dp; |
| 174 | + u32 addr; | |
| 149 | 175 | u8 sink_tp; |
| 150 | 176 | |
| 151 | 177 | OUTP_TRACE(&dp->outp, "training pattern %d", pattern); |
| 152 | 178 | dp->outp.ior->func->dp.pattern(dp->outp.ior, pattern); |
| 153 | 179 | |
| 154 | − nvkm_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); | |
| 180 | + if (lt->repeater) | |
| 181 | + addr = DPCD_LTTPR_PATTERN_SET(lt->repeater); | |
| 182 | + else | |
| 183 | + addr = DPCD_LC02; | |
| 184 | + | |
| 185 | + nvkm_rdaux(dp->aux, addr, &sink_tp, 1); | |
| 155 | 186 | sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; |
| 156 | − sink_tp |= pattern; | |
| 157 | − nvkm_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); | |
| 187 | + sink_tp |= (pattern != 4) ? pattern : 7; | |
| 188 | + | |
| 189 | + if (pattern != 0) | |
| 190 | + sink_tp |= DPCD_LC02_SCRAMBLING_DISABLE; | |
| 191 | + else | |
| 192 | + sink_tp &= ~DPCD_LC02_SCRAMBLING_DISABLE; | |
| 193 | + nvkm_wraux(dp->aux, addr, &sink_tp, 1); | |
| 158 | 194 | } |
| 159 | 195 | |
| 160 | 196 | static int |
| 161 | 197 | nvkm_dp_train_eq(struct lt_state *lt) |
| 162 | 198 | { |
| 199 | + struct nvkm_i2c_aux *aux = lt->dp->aux; | |
| 163 | 200 | bool eq_done = false, cr_done = true; |
| 164 | − int tries = 0, i; | |
| 201 | + int tries = 0, usec = 0, i; | |
| 202 | + u8 data; | |
| 165 | 203 | |
| 166 | − if (lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED) | |
| 167 | − nvkm_dp_train_pattern(lt, 3); | |
| 168 | − else | |
| 169 | − nvkm_dp_train_pattern(lt, 2); | |
| 204 | + if (lt->repeater) { | |
| 205 | + if (!nvkm_rdaux(aux, DPCD_LTTPR_AUX_RD_INTERVAL(lt->repeater), &data, sizeof(data))) | |
| 206 | + usec = (data & DPCD_RC0E_AUX_RD_INTERVAL) * 4000; | |
| 207 | + | |
| 208 | + nvkm_dp_train_pattern(lt, 4); | |
| 209 | + } else { | |
| 210 | + if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x14 && | |
| 211 | + lt->dp->dpcd[DPCD_RC03] & DPCD_RC03_TPS4_SUPPORTED) | |
| 212 | + nvkm_dp_train_pattern(lt, 4); | |
| 213 | + else | |
| 214 | + if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x12 && | |
| 215 | + lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED) | |
| 216 | + nvkm_dp_train_pattern(lt, 3); | |
| 217 | + else | |
| 218 | + nvkm_dp_train_pattern(lt, 2); | |
| 219 | + | |
| 220 | + usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000; | |
| 221 | + } | |
| 170 | 222 | |
| 171 | 223 | do { |
| 172 | 224 | if ((tries && |
| 173 | 225 | nvkm_dp_train_drive(lt, lt->pc2)) || |
| 174 | − nvkm_dp_train_sense(lt, lt->pc2, 400)) | |
| 226 | + nvkm_dp_train_sense(lt, lt->pc2, usec ? usec : 400)) | |
| 175 | 227 | break; |
| 176 | 228 | |
| 177 | 229 | eq_done = !!(lt->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); |
| @@ -193,13 +245,16 @@ nvkm_dp_train_cr(struct lt_state *lt) · 15 unmodified lines | ||
| 193 | 245 | { |
| 194 | 246 | bool cr_done = false, abort = false; |
| 195 | 247 | int voltage = lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET; |
| 196 | − int tries = 0, i; | |
| 248 | + int tries = 0, usec = 0, i; | |
| 197 | 249 | |
| 198 | 250 | nvkm_dp_train_pattern(lt, 1); |
| 199 | 251 | |
| 252 | + if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] < 0x14 && !lt->repeater) | |
| 253 | + usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000; | |
| 254 | + | |
| 200 | 255 | do { |
| 201 | 256 | if (nvkm_dp_train_drive(lt, false) || |
| 202 | − nvkm_dp_train_sense(lt, false, 100)) | |
| 257 | + nvkm_dp_train_sense(lt, false, usec ? usec : 100)) | |
| 203 | 258 | break; |
| 204 | 259 | |
| 205 | 260 | cr_done = true; |
| @@ -223,7 +278,7 @@ nvkm_dp_train_cr(struct lt_state *lt) · 17 unmodified lines | ||
| 223 | 278 | } |
| 224 | 279 | |
| 225 | 280 | static int |
| 226 | −nvkm_dp_train_links(struct nvkm_dp *dp) | |
| 281 | +nvkm_dp_train_links(struct nvkm_dp *dp, int rate) | |
| 227 | 282 | { |
| 228 | 283 | struct nvkm_ior *ior = dp->outp.ior; |
| 229 | 284 | struct nvkm_disp *disp = dp->outp.disp; |
| @@ -233,13 +288,15 @@ nvkm_dp_train_links(struct nvkm_dp *dp) · 3 unmodified lines | ||
| 233 | 288 | .dp = dp, |
| 234 | 289 | }; |
| 235 | 290 | u32 lnkcmp; |
| 236 | − u8 sink[2]; | |
| 291 | + u8 sink[2], data; | |
| 237 | 292 | int ret; |
| 238 | 293 | |
| 239 | 294 | OUTP_DBG(&dp->outp, "training %d x %d MB/s", |
| 240 | 295 | ior->dp.nr, ior->dp.bw * 27); |
| 241 | 296 | |
| 242 | 297 | /* Intersect misc. capabilities of the OR and sink. */ |
| 298 | + if (disp->engine.subdev.device->chipset < 0x110) | |
| 299 | + dp->dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED; | |
| 243 | 300 | if (disp->engine.subdev.device->chipset < 0xd0) |
| 244 | 301 | dp->dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED; |
| 245 | 302 | lt.pc2 = dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED; |
| @@ -287,8 +344,22 @@ nvkm_dp_train_links(struct nvkm_dp *dp) · 41 unmodified lines | ||
| 287 | 344 | |
| 288 | 345 | ior->func->dp.power(ior, ior->dp.nr); |
| 289 | 346 | |
| 347 | + /* Select LTTPR non-transparent mode if we have a valid configuration, | |
| 348 | + * use transparent mode otherwise. | |
| 349 | + */ | |
| 350 | + if (dp->lttpr[0] >= 0x14) { | |
| 351 | + data = DPCD_LTTPR_MODE_TRANSPARENT; | |
| 352 | + nvkm_wraux(dp->aux, DPCD_LTTPR_MODE, &data, sizeof(data)); | |
| 353 | + | |
| 354 | + if (dp->lttprs) { | |
| 355 | + data = DPCD_LTTPR_MODE_NON_TRANSPARENT; | |
| 356 | + nvkm_wraux(dp->aux, DPCD_LTTPR_MODE, &data, sizeof(data)); | |
| 357 | + lt.repeaters = dp->lttprs; | |
| 358 | + } | |
| 359 | + } | |
| 360 | + | |
| 290 | 361 | /* Set desired link configuration on the sink. */ |
| 291 | − sink[0] = ior->dp.bw; | |
| 362 | + sink[0] = (dp->rate[rate].dpcd < 0) ? ior->dp.bw : 0; | |
| 292 | 363 | sink[1] = ior->dp.nr; |
| 293 | 364 | if (ior->dp.ef) |
| 294 | 365 | sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; |
| @@ -297,12 +368,33 @@ nvkm_dp_train_links(struct nvkm_dp *dp) · 2 unmodified lines | ||
| 297 | 368 | if (ret) |
| 298 | 369 | return ret; |
| 299 | 370 | |
| 371 | + if (dp->rate[rate].dpcd >= 0) { | |
| 372 | + ret = nvkm_rdaux(dp->aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0])); | |
| 373 | + if (ret) | |
| 374 | + return ret; | |
| 375 | + | |
| 376 | + sink[0] &= ~DPCD_LC15_LINK_RATE_SET_MASK; | |
| 377 | + sink[0] |= dp->rate[rate].dpcd; | |
| 378 | + | |
| 379 | + ret = nvkm_wraux(dp->aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0])); | |
| 380 | + if (ret) | |
| 381 | + return ret; | |
| 382 | + } | |
| 383 | + | |
| 300 | 384 | /* Attempt to train the link in this configuration. */ |
| 301 | − memset(lt.stat, 0x00, sizeof(lt.stat)); | |
| 302 | − ret = nvkm_dp_train_cr(<); | |
| 303 | − if (ret == 0) | |
| 304 | − ret = nvkm_dp_train_eq(<); | |
| 305 | − nvkm_dp_train_pattern(<, 0); | |
| 385 | + for (lt.repeater = lt.repeaters; lt.repeater >= 0; lt.repeater--) { | |
| 386 | + if (lt.repeater) | |
| 387 | + OUTP_DBG(&dp->outp, "training LTTPR%d", lt.repeater); | |
| 388 | + else | |
| 389 | + OUTP_DBG(&dp->outp, "training sink"); | |
| 390 | + | |
| 391 | + memset(lt.stat, 0x00, sizeof(lt.stat)); | |
| 392 | + ret = nvkm_dp_train_cr(<); | |
| 393 | + if (ret == 0) | |
| 394 | + ret = nvkm_dp_train_eq(<); | |
| 395 | + nvkm_dp_train_pattern(<, 0); | |
| 396 | + } | |
| 397 | + | |
| 306 | 398 | return ret; |
| 307 | 399 | } |
| 308 | 400 | |
| @@ -345,63 +437,13 @@ nvkm_dp_train_init(struct nvkm_dp *dp) · 36 unmodified lines | ||
| 345 | 437 | } |
| 346 | 438 | } |
| 347 | 439 | |
| 348 | −static const struct dp_rates { | |
| 349 | − u32 rate; | |
| 350 | − u8 bw; | |
| 351 | − u8 nr; | |
| 352 | −} nvkm_dp_rates[] = { | |
| 353 | − { 2160000, 0x14, 4 }, | |
| 354 | − { 1080000, 0x0a, 4 }, | |
| 355 | − { 1080000, 0x14, 2 }, | |
| 356 | − { 648000, 0x06, 4 }, | |
| 357 | − { 540000, 0x0a, 2 }, | |
| 358 | − { 540000, 0x14, 1 }, | |
| 359 | − { 324000, 0x06, 2 }, | |
| 360 | − { 270000, 0x0a, 1 }, | |
| 361 | − { 162000, 0x06, 1 }, | |
| 362 | − {} | |
| 363 | −}; | |
| 364 | − | |
| 365 | 440 | static int |
| 366 | 441 | nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) |
| 367 | 442 | { |
| 368 | 443 | struct nvkm_ior *ior = dp->outp.ior; |
| 369 | − const u8 sink_nr = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT; | |
| 370 | − const u8 sink_bw = dp->dpcd[DPCD_RC01_MAX_LINK_RATE]; | |
| 371 | − const u8 outp_nr = dp->outp.info.dpconf.link_nr; | |
| 372 | − const u8 outp_bw = dp->outp.info.dpconf.link_bw; | |
| 373 | − const struct dp_rates *failsafe = NULL, *cfg; | |
| 374 | − int ret = -EINVAL; | |
| 444 | + int ret = -EINVAL, nr, rate; | |
| 375 | 445 | u8 pwr; |
| 376 | 446 | |
| 377 | − /* Find the lowest configuration of the OR that can support | |
| 378 | − * the required link rate. | |
| 379 | − * | |
| 380 | − * We will refuse to program the OR to lower rates, even if | |
| 381 | − * link training fails at higher rates (or even if the sink | |
| 382 | − * can't support the rate at all, though the DD is supposed | |
| 383 | − * to prevent such situations from happening). | |
| 384 | − * | |
| 385 | − * Attempting to do so can cause the entire display to hang, | |
| 386 | − * and it's better to have a failed modeset than that. | |
| 387 | − */ | |
| 388 | − for (cfg = nvkm_dp_rates; cfg->rate; cfg++) { | |
| 389 | − if (cfg->nr <= outp_nr && cfg->bw <= outp_bw) { | |
| 390 | − /* Try to respect sink limits too when selecting | |
| 391 | − * lowest link configuration. | |
| 392 | − */ | |
| 393 | − if (!failsafe || | |
| 394 | − (cfg->nr <= sink_nr && cfg->bw <= sink_bw)) | |
| 395 | − failsafe = cfg; | |
| 396 | − } | |
| 397 | − | |
| 398 | − if (failsafe && cfg[1].rate < dataKBps) | |
| 399 | − break; | |
| 400 | − } | |
| 401 | − | |
| 402 | − if (WARN_ON(!failsafe)) | |
| 403 | − return ret; | |
| 404 | − | |
| 405 | 447 | /* Ensure sink is not in a low-power state. */ |
| 406 | 448 | if (!nvkm_rdaux(dp->aux, DPCD_SC00, &pwr, 1)) { |
| 407 | 449 | if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { |
| @@ -411,25 +453,22 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) · 3 unmodified lines | ||
| 411 | 453 | } |
| 412 | 454 | } |
| 413 | 455 | |
| 456 | + ior->dp.mst = dp->lt.mst; | |
| 457 | + ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP; | |
| 458 | + ior->dp.nr = 0; | |
| 459 | + | |
| 414 | 460 | /* Link training. */ |
| 415 | − OUTP_DBG(&dp->outp, "training (min: %d x %d MB/s)", | |
| 416 | − failsafe->nr, failsafe->bw * 27); | |
| 461 | + OUTP_DBG(&dp->outp, "training"); | |
| 417 | 462 | nvkm_dp_train_init(dp); |
| 418 | − for (cfg = nvkm_dp_rates; ret < 0 && cfg <= failsafe; cfg++) { | |
| 419 | − /* Skip configurations not supported by both OR and sink. */ | |
| 420 | − if ((cfg->nr > outp_nr || cfg->bw > outp_bw || | |
| 421 | − cfg->nr > sink_nr || cfg->bw > sink_bw)) { | |
| 422 | − if (cfg != failsafe) | |
| 423 | − continue; | |
| 424 | − OUTP_ERR(&dp->outp, "link rate unsupported by sink"); | |
| 463 | + for (nr = dp->links; ret < 0 && nr; nr >>= 1) { | |
| 464 | + for (rate = 0; ret < 0 && rate < dp->rates; rate++) { | |
| 465 | + if (dp->rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) { | |
| 466 | + /* Program selected link configuration. */ | |
| 467 | + ior->dp.bw = dp->rate[rate].rate / 27000; | |
| 468 | + ior->dp.nr = nr; | |
| 469 | + ret = nvkm_dp_train_links(dp, rate); | |
| 470 | + } | |
| 425 | 471 | } |
| 426 | − ior->dp.mst = dp->lt.mst; | |
| 427 | − ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP; | |
| 428 | − ior->dp.bw = cfg->bw; | |
| 429 | − ior->dp.nr = cfg->nr; | |
| 430 | − | |
| 431 | − /* Program selected link configuration. */ | |
| 432 | − ret = nvkm_dp_train_links(dp); | |
| 433 | 472 | } |
| 434 | 473 | nvkm_dp_train_fini(dp); |
| 435 | 474 | if (ret < 0) |
| @@ -526,6 +565,47 @@ done: · 90 unmodified lines | ||
| 526 | 565 | return ret; |
| 527 | 566 | } |
| 528 | 567 | |
| 568 | +static bool | |
| 569 | +nvkm_dp_enable_supported_link_rates(struct nvkm_dp *dp) | |
| 570 | +{ | |
| 571 | + u8 sink_rates[DPCD_RC10_SUPPORTED_LINK_RATES__SIZE]; | |
| 572 | + int i, j, k; | |
| 573 | + | |
| 574 | + if (dp->outp.conn->info.type != DCB_CONNECTOR_eDP || | |
| 575 | + dp->dpcd[DPCD_RC00_DPCD_REV] < 0x13 || | |
| 576 | + nvkm_rdaux(dp->aux, DPCD_RC10_SUPPORTED_LINK_RATES(0), sink_rates, sizeof(sink_rates))) | |
| 577 | + return false; | |
| 578 | + | |
| 579 | + for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) { | |
| 580 | + const u32 rate = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10; | |
| 581 | + | |
| 582 | + if (!rate || WARN_ON(dp->rates == ARRAY_SIZE(dp->rate))) | |
| 583 | + break; | |
| 584 | + | |
| 585 | + if (rate > dp->outp.info.dpconf.link_bw * 27000) { | |
| 586 | + OUTP_DBG(&dp->outp, "rate %d !outp", rate); | |
| 587 | + continue; | |
| 588 | + } | |
| 589 | + | |
| 590 | + for (j = 0; j < dp->rates; j++) { | |
| 591 | + if (rate > dp->rate[j].rate) { | |
| 592 | + for (k = dp->rates; k > j; k--) | |
| 593 | + dp->rate[k] = dp->rate[k - 1]; | |
| 594 | + break; | |
| 595 | + } | |
| 596 | + } | |
| 597 | + | |
| 598 | + dp->rate[j].dpcd = i / 2; | |
| 599 | + dp->rate[j].rate = rate; | |
| 600 | + dp->rates++; | |
| 601 | + } | |
| 602 | + | |
| 603 | + for (i = 0; i < dp->rates; i++) | |
| 604 | + OUTP_DBG(&dp->outp, "link_rate[%d] = %d", dp->rate[i].dpcd, dp->rate[i].rate); | |
| 605 | + | |
| 606 | + return dp->rates != 0; | |
| 607 | +} | |
| 608 | + | |
| 529 | 609 | static bool |
| 530 | 610 | nvkm_dp_enable(struct nvkm_dp *dp, bool enable) |
| 531 | 611 | { |
| @@ -538,9 +618,60 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable) · 6 unmodified lines | ||
| 538 | 618 | dp->present = true; |
| 539 | 619 | } |
| 540 | 620 | |
| 541 | − if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, | |
| 542 | − sizeof(dp->dpcd))) | |
| 621 | + /* Detect any LTTPRs before reading DPCD receiver caps. */ | |
| 622 | + if (!nvkm_rdaux(aux, DPCD_LTTPR_REV, dp->lttpr, sizeof(dp->lttpr)) && | |
| 623 | + dp->lttpr[0] >= 0x14 && dp->lttpr[2]) { | |
| 624 | + switch (dp->lttpr[2]) { | |
| 625 | + case 0x80: dp->lttprs = 1; break; | |
| 626 | + case 0x40: dp->lttprs = 2; break; | |
| 627 | + case 0x20: dp->lttprs = 3; break; | |
| 628 | + case 0x10: dp->lttprs = 4; break; | |
| 629 | + case 0x08: dp->lttprs = 5; break; | |
| 630 | + case 0x04: dp->lttprs = 6; break; | |
| 631 | + case 0x02: dp->lttprs = 7; break; | |
| 632 | + case 0x01: dp->lttprs = 8; break; | |
| 633 | + default: | |
| 634 | + /* Unknown LTTPR count, we'll switch to transparent mode. */ | |
| 635 | + WARN_ON(1); | |
| 636 | + dp->lttprs = 0; | |
| 637 | + break; | |
| 638 | + } | |
| 639 | + } else { | |
| 640 | + /* No LTTPR support, or zero LTTPR count - don't touch it at all. */ | |
| 641 | + memset(dp->lttpr, 0x00, sizeof(dp->lttpr)); | |
| 642 | + } | |
| 643 | + | |
| 644 | + if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, sizeof(dp->dpcd))) { | |
| 645 | + const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 }; | |
| 646 | + const u8 *rate; | |
| 647 | + int rate_max; | |
| 648 | + | |
| 649 | + dp->rates = 0; | |
| 650 | + dp->links = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT; | |
| 651 | + dp->links = min(dp->links, dp->outp.info.dpconf.link_nr); | |
| 652 | + if (dp->lttprs && dp->lttpr[4]) | |
| 653 | + dp->links = min_t(int, dp->links, dp->lttpr[4]); | |
| 654 | + | |
| 655 | + rate_max = dp->dpcd[DPCD_RC01_MAX_LINK_RATE]; | |
| 656 | + rate_max = min(rate_max, dp->outp.info.dpconf.link_bw); | |
| 657 | + if (dp->lttprs && dp->lttpr[1]) | |
| 658 | + rate_max = min_t(int, rate_max, dp->lttpr[1]); | |
| 659 | + | |
| 660 | + if (!nvkm_dp_enable_supported_link_rates(dp)) { | |
| 661 | + for (rate = rates; *rate; rate++) { | |
| 662 | + if (*rate <= rate_max) { | |
| 663 | + if (WARN_ON(dp->rates == ARRAY_SIZE(dp->rate))) | |
| 664 | + break; | |
| 665 | + | |
| 666 | + dp->rate[dp->rates].dpcd = -1; | |
| 667 | + dp->rate[dp->rates].rate = *rate * 27000; | |
| 668 | + dp->rates++; | |
| 669 | + } | |
| 670 | + } | |
| 671 | + } | |
| 672 | + | |
| 543 | 673 | return true; |
| 674 | + } | |
| 544 | 675 | } |
| 545 | 676 | |
| 546 | 677 | if (dp->present) { |
| @@ -9,10 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <subdev/bios/dp.h> |
| 10 | 10 | |
| 11 | 11 | struct nvkm_dp { |
| 12 | − union { | |
| 13 | − struct nvkm_outp base; | |
| 14 | − struct nvkm_outp outp; | |
| 15 | − }; | |
| 12 | + struct nvkm_outp outp; | |
| 16 | 13 | |
| 17 | 14 | struct nvbios_dpout info; |
| 18 | 15 | u8 version; |
| @@ -21,8 +18,17 @@ struct nvkm_dp { · 2 unmodified lines | ||
| 21 | 18 | |
| 22 | 19 | struct nvkm_notify hpd; |
| 23 | 20 | bool present; |
| 21 | + u8 lttpr[6]; | |
| 22 | + u8 lttprs; | |
| 24 | 23 | u8 dpcd[16]; |
| 25 | 24 | |
| 25 | + struct { | |
| 26 | + int dpcd; /* -1, or index into SUPPORTED_LINK_RATES table */ | |
| 27 | + u32 rate; | |
| 28 | + } rate[8]; | |
| 29 | + int rates; | |
| 30 | + int links; | |
| 31 | + | |
| 26 | 32 | struct mutex mutex; |
| 27 | 33 | struct { |
| 28 | 34 | atomic_t done; |
| @@ -42,8 +48,12 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); · 13 unmodified lines | ||
| 42 | 48 | #define DPCD_RC02_TPS3_SUPPORTED 0x40 |
| 43 | 49 | #define DPCD_RC02_MAX_LANE_COUNT 0x1f |
| 44 | 50 | #define DPCD_RC03 0x00003 |
| 51 | +#define DPCD_RC03_TPS4_SUPPORTED 0x80 | |
| 45 | 52 | #define DPCD_RC03_MAX_DOWNSPREAD 0x01 |
| 46 | −#define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e | |
| 53 | +#define DPCD_RC0E 0x0000e | |
| 54 | +#define DPCD_RC0E_AUX_RD_INTERVAL 0x7f | |
| 55 | +#define DPCD_RC10_SUPPORTED_LINK_RATES(i) 0x00010 | |
| 56 | +#define DPCD_RC10_SUPPORTED_LINK_RATES__SIZE 16 | |
| 47 | 57 | |
| 48 | 58 | /* DPCD Link Configuration */ |
| 49 | 59 | #define DPCD_LC00_LINK_BW_SET 0x00100 |
| @@ -51,7 +61,8 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); · 1 unmodified line | ||
| 51 | 61 | #define DPCD_LC01_ENHANCED_FRAME_EN 0x80 |
| 52 | 62 | #define DPCD_LC01_LANE_COUNT_SET 0x1f |
| 53 | 63 | #define DPCD_LC02 0x00102 |
| 54 | −#define DPCD_LC02_TRAINING_PATTERN_SET 0x03 | |
| 64 | +#define DPCD_LC02_TRAINING_PATTERN_SET 0x0f | |
| 65 | +#define DPCD_LC02_SCRAMBLING_DISABLE 0x20 | |
| 55 | 66 | #define DPCD_LC03(l) ((l) + 0x00103) |
| 56 | 67 | #define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20 |
| 57 | 68 | #define DPCD_LC03_PRE_EMPHASIS_SET 0x18 |
| @@ -67,6 +78,8 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); · 9 unmodified lines | ||
| 67 | 78 | #define DPCD_LC10_LANE3_POST_CURSOR2_SET 0x30 |
| 68 | 79 | #define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED 0x04 |
| 69 | 80 | #define DPCD_LC10_LANE2_POST_CURSOR2_SET 0x03 |
| 81 | +#define DPCD_LC15_LINK_RATE_SET 0x00115 | |
| 82 | +#define DPCD_LC15_LINK_RATE_SET_MASK 0x07 | |
| 70 | 83 | |
| 71 | 84 | /* DPCD Link/Sink Status */ |
| 72 | 85 | #define DPCD_LS02 0x00202 |
| @@ -108,4 +121,14 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); · 35 unmodified lines | ||
| 108 | 121 | #define DPCD_SC00_SET_POWER 0x03 |
| 109 | 122 | #define DPCD_SC00_SET_POWER_D0 0x01 |
| 110 | 123 | #define DPCD_SC00_SET_POWER_D3 0x03 |
| 124 | + | |
| 125 | +#define DPCD_LTTPR_REV 0xf0000 | |
| 126 | +#define DPCD_LTTPR_MODE 0xf0003 | |
| 127 | +#define DPCD_LTTPR_MODE_TRANSPARENT 0x55 | |
| 128 | +#define DPCD_LTTPR_MODE_NON_TRANSPARENT 0xaa | |
| 129 | +#define DPCD_LTTPR_PATTERN_SET(i) ((i - 1) * 0x50 + 0xf0010) | |
| 130 | +#define DPCD_LTTPR_LANE0_SET(i) ((i - 1) * 0x50 + 0xf0011) | |
| 131 | +#define DPCD_LTTPR_AUX_RD_INTERVAL(i) ((i - 1) * 0x50 + 0xf0020) | |
| 132 | +#define DPCD_LTTPR_LANE0_1_STATUS(i) ((i - 1) * 0x50 + 0xf0030) | |
| 133 | +#define DPCD_LTTPR_LANE0_1_ADJUST(i) ((i - 1) * 0x50 + 0xf0033) | |
| 111 | 134 | #endif |
| @@ -77,7 +77,18 @@ g94_sor_dp_pattern(struct nvkm_ior *sor, int pattern) · 76 unmodified lines | ||
| 77 | 77 | { |
| 78 | 78 | struct nvkm_device *device = sor->disp->engine.subdev.device; |
| 79 | 79 | const u32 loff = nv50_sor_link(sor); |
| 80 | − nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24); | |
| 80 | + u32 data; | |
| 81 | + | |
| 82 | + switch (pattern) { | |
| 83 | + case 0: data = 0x00001000; break; | |
| 84 | + case 1: data = 0x01000000; break; | |
| 85 | + case 2: data = 0x02000000; break; | |
| 86 | + default: | |
| 87 | + WARN_ON(1); | |
| 88 | + return; | |
| 89 | + } | |
| 90 | + | |
| 91 | + nvkm_mask(device, 0x61c10c + loff, 0x0f001000, data); | |
| 81 | 92 | } |
| 82 | 93 | |
| 83 | 94 | void |
| @@ -37,6 +37,10 @@ ga102_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) · 36 unmodified lines | ||
| 37 | 37 | case 0x0a: clksor |= 0x00040000; break; |
| 38 | 38 | case 0x14: clksor |= 0x00080000; break; |
| 39 | 39 | case 0x1e: clksor |= 0x000c0000; break; |
| 40 | + case 0x08: clksor |= 0x00100000; break; | |
| 41 | + case 0x09: clksor |= 0x00140000; break; | |
| 42 | + case 0x0c: clksor |= 0x00180000; break; | |
| 43 | + case 0x10: clksor |= 0x001c0000; break; | |
| 40 | 44 | default: |
| 41 | 45 | WARN_ON(1); |
| 42 | 46 | return -EINVAL; |
| @@ -92,7 +92,19 @@ gf119_sor_dp_pattern(struct nvkm_ior *sor, int pattern) · 91 unmodified lines | ||
| 92 | 92 | { |
| 93 | 93 | struct nvkm_device *device = sor->disp->engine.subdev.device; |
| 94 | 94 | const u32 soff = nv50_ior_base(sor); |
| 95 | − nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern); | |
| 95 | + u32 data; | |
| 96 | + | |
| 97 | + switch (pattern) { | |
| 98 | + case 0: data = 0x10101010; break; | |
| 99 | + case 1: data = 0x01010101; break; | |
| 100 | + case 2: data = 0x02020202; break; | |
| 101 | + case 3: data = 0x03030303; break; | |
| 102 | + default: | |
| 103 | + WARN_ON(1); | |
| 104 | + return; | |
| 105 | + } | |
| 106 | + | |
| 107 | + nvkm_mask(device, 0x61c110 + soff, 0x1f1f1f1f, data); | |
| 96 | 108 | } |
| 97 | 109 | |
| 98 | 110 | int |
| @@ -28,11 +28,23 @@ gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern) · 27 unmodified lines | ||
| 28 | 28 | { |
| 29 | 29 | struct nvkm_device *device = sor->disp->engine.subdev.device; |
| 30 | 30 | const u32 soff = nv50_ior_base(sor); |
| 31 | − const u32 data = 0x01010101 * pattern; | |
| 31 | + u32 mask = 0x1f1f1f1f, data; | |
| 32 | + | |
| 33 | + switch (pattern) { | |
| 34 | + case 0: data = 0x10101010; break; | |
| 35 | + case 1: data = 0x01010101; break; | |
| 36 | + case 2: data = 0x02020202; break; | |
| 37 | + case 3: data = 0x03030303; break; | |
| 38 | + case 4: data = 0x1b1b1b1b; break; | |
| 39 | + default: | |
| 40 | + WARN_ON(1); | |
| 41 | + return; | |
| 42 | + } | |
| 43 | + | |
| 32 | 44 | if (sor->asy.link & 1) |
| 33 | − nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data); | |
| 45 | + nvkm_mask(device, 0x61c110 + soff, mask, data); | |
| 34 | 46 | else |
| 35 | − nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data); | |
| 47 | + nvkm_mask(device, 0x61c12c + soff, mask, data); | |
| 36 | 48 | } |
| 37 | 49 | |
| 38 | 50 | static const struct nvkm_ior_func |
| @@ -142,11 +142,12 @@ nvkm_acr_hsfw_load_bl(struct nvkm_acr *acr, const char *name, int ver, · 141 unmodified lines | ||
| 142 | 142 | |
| 143 | 143 | hsfw->imem_size = desc->code_size; |
| 144 | 144 | hsfw->imem_tag = desc->start_tag; |
| 145 | − hsfw->imem = kmalloc(desc->code_size, GFP_KERNEL); | |
| 146 | − memcpy(hsfw->imem, data + desc->code_off, desc->code_size); | |
| 147 | − | |
| 145 | + hsfw->imem = kmemdup(data + desc->code_off, desc->code_size, GFP_KERNEL); | |
| 148 | 146 | nvkm_firmware_put(fw); |
| 149 | − return 0; | |
| 147 | + if (!hsfw->imem) | |
| 148 | + return -ENOMEM; | |
| 149 | + else | |
| 150 | + return 0; | |
| 150 | 151 | } |
| 151 | 152 | |
| 152 | 153 | int |
| @@ -93,6 +93,7 @@ struct dma_buf *omap_gem_prime_export(struct drm_gem_object *obj, int flags) · 92 unmodified lines | ||
| 93 | 93 | exp_info.size = omap_gem_mmap_size(obj); |
| 94 | 94 | exp_info.flags = flags; |
| 95 | 95 | exp_info.priv = obj; |
| 96 | + exp_info.resv = obj->resv; | |
| 96 | 97 | |
| 97 | 98 | return drm_gem_dmabuf_export(obj->dev, &exp_info); |
| 98 | 99 | } |
| @@ -86,7 +86,7 @@ static const struct panel_init_cmd boe_tv110c9m_init_cmd[] = { · 85 unmodified lines | ||
| 86 | 86 | _INIT_DCS_CMD(0x0F, 0x73), |
| 87 | 87 | _INIT_DCS_CMD(0x95, 0xE6), |
| 88 | 88 | _INIT_DCS_CMD(0x96, 0xF0), |
| 89 | − _INIT_DCS_CMD(0x30, 0x11), | |
| 89 | + _INIT_DCS_CMD(0x30, 0x00), | |
| 90 | 90 | _INIT_DCS_CMD(0x6D, 0x66), |
| 91 | 91 | _INIT_DCS_CMD(0x75, 0xA2), |
| 92 | 92 | _INIT_DCS_CMD(0x77, 0x3B), |
| @@ -112,17 +112,17 @@ static const struct panel_init_cmd boe_tv110c9m_init_cmd[] = { · 19 unmodified lines | ||
| 112 | 112 | _INIT_DCS_CMD(0xB1, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), |
| 113 | 113 | _INIT_DCS_CMD(0xB2, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), |
| 114 | 114 | |
| 115 | − _INIT_DCS_CMD(0xB3, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0), | |
| 115 | + _INIT_DCS_CMD(0xB3, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0), | |
| 116 | 116 | _INIT_DCS_CMD(0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1), |
| 117 | 117 | _INIT_DCS_CMD(0xB5, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), |
| 118 | 118 | _INIT_DCS_CMD(0xB6, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), |
| 119 | − _INIT_DCS_CMD(0xB7, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0), | |
| 119 | + _INIT_DCS_CMD(0xB7, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0), | |
| 120 | 120 | |
| 121 | 121 | _INIT_DCS_CMD(0xB8, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1), |
| 122 | 122 | _INIT_DCS_CMD(0xB9, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), |
| 123 | 123 | _INIT_DCS_CMD(0xBA, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), |
| 124 | 124 | |
| 125 | − _INIT_DCS_CMD(0xBB, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0), | |
| 125 | + _INIT_DCS_CMD(0xBB, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0), | |
| 126 | 126 | _INIT_DCS_CMD(0xFF, 0x24), |
| 127 | 127 | _INIT_DCS_CMD(0xFB, 0x01), |
| 128 | 128 | |
| @@ -36,8 +36,8 @@ · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | #include <drm/drm_crtc.h> |
| 38 | 38 | #include <drm/drm_device.h> |
| 39 | −#include <drm/drm_dp_aux_bus.h> | |
| 40 | −#include <drm/drm_dp_helper.h> | |
| 39 | +#include <drm/dp/drm_dp_aux_bus.h> | |
| 40 | +#include <drm/dp/drm_dp_helper.h> | |
| 41 | 41 | #include <drm/drm_panel.h> |
| 42 | 42 | |
| 43 | 43 | /** |
| @@ -1745,6 +1745,19 @@ static const struct panel_delay delay_200_500_e50 = { · 1701 unmodified lines | ||
| 1745 | 1745 | .enable = 50, |
| 1746 | 1746 | }; |
| 1747 | 1747 | |
| 1748 | +static const struct panel_delay delay_200_500_e80_d50 = { | |
| 1749 | + .hpd_absent = 200, | |
| 1750 | + .unprepare = 500, | |
| 1751 | + .enable = 80, | |
| 1752 | + .disable = 50, | |
| 1753 | +}; | |
| 1754 | + | |
| 1755 | +static const struct panel_delay delay_100_500_e200 = { | |
| 1756 | + .hpd_absent = 100, | |
| 1757 | + .unprepare = 500, | |
| 1758 | + .enable = 200, | |
| 1759 | +}; | |
| 1760 | + | |
| 1748 | 1761 | #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ |
| 1749 | 1762 | { \ |
| 1750 | 1763 | .name = _name, \ |
| @@ -1768,13 +1781,17 @@ static const struct edp_panel_entry edp_panels[] = { · 17 unmodified lines | ||
| 1768 | 1781 | EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), |
| 1769 | 1782 | EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), |
| 1770 | 1783 | EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), |
| 1784 | + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), | |
| 1771 | 1785 | |
| 1772 | 1786 | EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), |
| 1773 | 1787 | |
| 1774 | 1788 | EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), |
| 1789 | + EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), | |
| 1775 | 1790 | |
| 1776 | 1791 | EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"), |
| 1777 | 1792 | |
| 1793 | + EDP_PANEL_ENTRY('S', 'T', 'A', 0x0100, &delay_100_500_e200, "2081116HHD028001-51D"), | |
| 1794 | + | |
| 1778 | 1795 | { /* sentinal */ } |
| 1779 | 1796 | }; |
| 1780 | 1797 | |
| @@ -14,8 +14,8 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/pm_runtime.h> |
| 15 | 15 | #include <linux/regulator/consumer.h> |
| 16 | 16 | |
| 17 | −#include <drm/drm_dp_aux_bus.h> | |
| 18 | −#include <drm/drm_dp_helper.h> | |
| 17 | +#include <drm/dp/drm_dp_aux_bus.h> | |
| 18 | +#include <drm/dp/drm_dp_helper.h> | |
| 19 | 19 | #include <drm/drm_edid.h> |
| 20 | 20 | #include <drm/drm_panel.h> |
| 21 | 21 | |
| @@ -2525,6 +2525,36 @@ static const struct panel_desc mitsubishi_aa070mc01 = { · 2524 unmodified lines | ||
| 2525 | 2525 | .bus_flags = DRM_BUS_FLAG_DE_HIGH, |
| 2526 | 2526 | }; |
| 2527 | 2527 | |
| 2528 | +static const struct display_timing multi_inno_mi0700s4t_6_timing = { | |
| 2529 | + .pixelclock = { 29000000, 33000000, 38000000 }, | |
| 2530 | + .hactive = { 800, 800, 800 }, | |
| 2531 | + .hfront_porch = { 180, 210, 240 }, | |
| 2532 | + .hback_porch = { 16, 16, 16 }, | |
| 2533 | + .hsync_len = { 30, 30, 30 }, | |
| 2534 | + .vactive = { 480, 480, 480 }, | |
| 2535 | + .vfront_porch = { 12, 22, 32 }, | |
| 2536 | + .vback_porch = { 10, 10, 10 }, | |
| 2537 | + .vsync_len = { 13, 13, 13 }, | |
| 2538 | + .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW | | |
| 2539 | + DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE | | |
| 2540 | + DISPLAY_FLAGS_SYNC_POSEDGE, | |
| 2541 | +}; | |
| 2542 | + | |
| 2543 | +static const struct panel_desc multi_inno_mi0700s4t_6 = { | |
| 2544 | + .timings = &multi_inno_mi0700s4t_6_timing, | |
| 2545 | + .num_timings = 1, | |
| 2546 | + .bpc = 8, | |
| 2547 | + .size = { | |
| 2548 | + .width = 154, | |
| 2549 | + .height = 86, | |
| 2550 | + }, | |
| 2551 | + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | |
| 2552 | + .bus_flags = DRM_BUS_FLAG_DE_HIGH | | |
| 2553 | + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | | |
| 2554 | + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE, | |
| 2555 | + .connector_type = DRM_MODE_CONNECTOR_DPI, | |
| 2556 | +}; | |
| 2557 | + | |
| 2528 | 2558 | static const struct display_timing multi_inno_mi1010ait_1cp_timing = { |
| 2529 | 2559 | .pixelclock = { 68900000, 70000000, 73400000 }, |
| 2530 | 2560 | .hactive = { 1280, 1280, 1280 }, |
| @@ -3871,6 +3901,9 @@ static const struct of_device_id platform_of_match[] = { · 1340 unmodified lines | ||
| 3871 | 3901 | }, { |
| 3872 | 3902 | .compatible = "mitsubishi,aa070mc01-ca1", |
| 3873 | 3903 | .data = &mitsubishi_aa070mc01, |
| 3904 | + }, { | |
| 3905 | + .compatible = "multi-inno,mi0700s4t-6", | |
| 3906 | + .data = &multi_inno_mi0700s4t_6, | |
| 3874 | 3907 | }, { |
| 3875 | 3908 | .compatible = "multi-inno,mi1010ait-1cp", |
| 3876 | 3909 | .data = &multi_inno_mi1010ait_1cp, |
| @@ -12,24 +12,6 @@ enum panfrost_hw_feature { · 11 unmodified lines | ||
| 12 | 12 | HW_FEATURE_JOBCHAIN_DISAMBIGUATION, |
| 13 | 13 | HW_FEATURE_PWRON_DURING_PWROFF_TRANS, |
| 14 | 14 | HW_FEATURE_XAFFINITY, |
| 15 | − HW_FEATURE_OUT_OF_ORDER_EXEC, | |
| 16 | − HW_FEATURE_MRT, | |
| 17 | − HW_FEATURE_BRNDOUT_CC, | |
| 18 | − HW_FEATURE_INTERPIPE_REG_ALIASING, | |
| 19 | − HW_FEATURE_LD_ST_TILEBUFFER, | |
| 20 | − HW_FEATURE_MSAA_16X, | |
| 21 | − HW_FEATURE_32_BIT_UNIFORM_ADDRESS, | |
| 22 | − HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, | |
| 23 | − HW_FEATURE_OPTIMIZED_COVERAGE_MASK, | |
| 24 | − HW_FEATURE_T7XX_PAIRING_RULES, | |
| 25 | − HW_FEATURE_LD_ST_LEA_TEX, | |
| 26 | − HW_FEATURE_LINEAR_FILTER_FLOAT, | |
| 27 | − HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4, | |
| 28 | − HW_FEATURE_IMAGES_IN_FRAGMENT_SHADERS, | |
| 29 | − HW_FEATURE_TEST4_DATUM_MODE, | |
| 30 | − HW_FEATURE_NEXT_INSTRUCTION_TYPE, | |
| 31 | − HW_FEATURE_BRNDOUT_KILL, | |
| 32 | − HW_FEATURE_WARPING, | |
| 33 | 15 | HW_FEATURE_V4, |
| 34 | 16 | HW_FEATURE_FLUSH_REDUCTION, |
| 35 | 17 | HW_FEATURE_PROTECTED_MODE, |
| @@ -42,128 +24,31 @@ enum panfrost_hw_feature { · 6 unmodified lines | ||
| 42 | 24 | }; |
| 43 | 25 | |
| 44 | 26 | #define hw_features_t600 (\ |
| 45 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 46 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 47 | 27 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 48 | 28 | BIT_ULL(HW_FEATURE_V4)) |
| 49 | 29 | |
| 50 | −#define hw_features_t620 (\ | |
| 51 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 52 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 53 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 54 | − BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | |
| 55 | − BIT_ULL(HW_FEATURE_V4)) | |
| 56 | − | |
| 57 | −#define hw_features_t720 (\ | |
| 58 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 59 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 60 | − BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | |
| 61 | − BIT_ULL(HW_FEATURE_OPTIMIZED_COVERAGE_MASK) | \ | |
| 62 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 63 | − BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | |
| 64 | − BIT_ULL(HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4) | \ | |
| 65 | − BIT_ULL(HW_FEATURE_WARPING) | \ | |
| 66 | − BIT_ULL(HW_FEATURE_V4)) | |
| 30 | +#define hw_features_t620 hw_features_t600 | |
| 67 | 31 | |
| 32 | +#define hw_features_t720 hw_features_t600 | |
| 68 | 33 | |
| 69 | 34 | #define hw_features_t760 (\ |
| 70 | 35 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 71 | 36 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 72 | 37 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 73 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 74 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 75 | − BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | |
| 76 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 77 | − BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | |
| 78 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 79 | − BIT_ULL(HW_FEATURE_MRT) | \ | |
| 80 | − BIT_ULL(HW_FEATURE_MSAA_16X) | \ | |
| 81 | − BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | |
| 82 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 83 | − BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | |
| 84 | 38 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) |
| 85 | 39 | |
| 86 | −// T860 | |
| 87 | −#define hw_features_t860 (\ | |
| 88 | − BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | |
| 89 | − BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | |
| 90 | − BIT_ULL(HW_FEATURE_XAFFINITY) | \ | |
| 91 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 92 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 93 | − BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | |
| 94 | − BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | |
| 95 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 96 | − BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | |
| 97 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 98 | − BIT_ULL(HW_FEATURE_MRT) | \ | |
| 99 | − BIT_ULL(HW_FEATURE_MSAA_16X) | \ | |
| 100 | − BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | |
| 101 | − BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | |
| 102 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 103 | − BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | |
| 104 | − BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) | |
| 40 | +#define hw_features_t860 hw_features_t760 | |
| 105 | 41 | |
| 106 | −#define hw_features_t880 hw_features_t860 | |
| 42 | +#define hw_features_t880 hw_features_t760 | |
| 107 | 43 | |
| 108 | −#define hw_features_t830 (\ | |
| 109 | − BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | |
| 110 | − BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | |
| 111 | − BIT_ULL(HW_FEATURE_XAFFINITY) | \ | |
| 112 | − BIT_ULL(HW_FEATURE_WARPING) | \ | |
| 113 | − BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | |
| 114 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 115 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 116 | − BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | |
| 117 | − BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | |
| 118 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 119 | − BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | |
| 120 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 121 | − BIT_ULL(HW_FEATURE_MRT) | \ | |
| 122 | − BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | |
| 123 | − BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | |
| 124 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 125 | − BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | |
| 126 | − BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) | |
| 44 | +#define hw_features_t830 hw_features_t760 | |
| 127 | 45 | |
| 128 | −#define hw_features_t820 (\ | |
| 129 | − BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | |
| 130 | − BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | |
| 131 | − BIT_ULL(HW_FEATURE_XAFFINITY) | \ | |
| 132 | − BIT_ULL(HW_FEATURE_WARPING) | \ | |
| 133 | − BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | |
| 134 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 135 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 136 | − BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | |
| 137 | − BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | |
| 138 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 139 | − BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | |
| 140 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 141 | − BIT_ULL(HW_FEATURE_MRT) | \ | |
| 142 | − BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | |
| 143 | − BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | |
| 144 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 145 | − BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | |
| 146 | − BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) | |
| 46 | +#define hw_features_t820 hw_features_t760 | |
| 147 | 47 | |
| 148 | 48 | #define hw_features_g71 (\ |
| 149 | 49 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 150 | 50 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 151 | 51 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 152 | − BIT_ULL(HW_FEATURE_WARPING) | \ | |
| 153 | − BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | |
| 154 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 155 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 156 | − BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | |
| 157 | − BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | |
| 158 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 159 | − BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | |
| 160 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 161 | − BIT_ULL(HW_FEATURE_MRT) | \ | |
| 162 | − BIT_ULL(HW_FEATURE_MSAA_16X) | \ | |
| 163 | − BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | |
| 164 | − BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | |
| 165 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 166 | − BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | |
| 167 | 52 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 168 | 53 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ |
| 169 | 54 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ |
| @@ -173,71 +58,18 @@ enum panfrost_hw_feature { · 3 unmodified lines | ||
| 173 | 58 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 174 | 59 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 175 | 60 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 176 | − BIT_ULL(HW_FEATURE_WARPING) | \ | |
| 177 | − BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | |
| 178 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 179 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 180 | − BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | |
| 181 | − BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | |
| 182 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 183 | − BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | |
| 184 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 185 | − BIT_ULL(HW_FEATURE_MRT) | \ | |
| 186 | − BIT_ULL(HW_FEATURE_MSAA_16X) | \ | |
| 187 | − BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | |
| 188 | − BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | |
| 189 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 190 | − BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | |
| 191 | 61 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 192 | 62 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ |
| 193 | 63 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ |
| 194 | 64 | BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ |
| 195 | 65 | BIT_ULL(HW_FEATURE_COHERENCY_REG)) |
| 196 | 66 | |
| 197 | −#define hw_features_g51 (\ | |
| 198 | − BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | |
| 199 | − BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | |
| 200 | − BIT_ULL(HW_FEATURE_XAFFINITY) | \ | |
| 201 | − BIT_ULL(HW_FEATURE_WARPING) | \ | |
| 202 | − BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | |
| 203 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 204 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 205 | − BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | |
| 206 | − BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | |
| 207 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 208 | − BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | |
| 209 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 210 | − BIT_ULL(HW_FEATURE_MRT) | \ | |
| 211 | − BIT_ULL(HW_FEATURE_MSAA_16X) | \ | |
| 212 | − BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | |
| 213 | − BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | |
| 214 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 215 | − BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | |
| 216 | − BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | |
| 217 | − BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ | |
| 218 | − BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ | |
| 219 | − BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ | |
| 220 | − BIT_ULL(HW_FEATURE_COHERENCY_REG)) | |
| 67 | +#define hw_features_g51 hw_features_g72 | |
| 221 | 68 | |
| 222 | 69 | #define hw_features_g52 (\ |
| 223 | 70 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 224 | 71 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 225 | 72 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 226 | − BIT_ULL(HW_FEATURE_WARPING) | \ | |
| 227 | − BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | |
| 228 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 229 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 230 | − BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | |
| 231 | − BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | |
| 232 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 233 | − BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | |
| 234 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 235 | − BIT_ULL(HW_FEATURE_MRT) | \ | |
| 236 | − BIT_ULL(HW_FEATURE_MSAA_16X) | \ | |
| 237 | − BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | |
| 238 | − BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | |
| 239 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 240 | − BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | |
| 241 | 73 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 242 | 74 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ |
| 243 | 75 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ |
| @@ -248,21 +80,6 @@ enum panfrost_hw_feature { · 4 unmodified lines | ||
| 248 | 80 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 249 | 81 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 250 | 82 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 251 | − BIT_ULL(HW_FEATURE_WARPING) | \ | |
| 252 | − BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | |
| 253 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 254 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 255 | − BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | |
| 256 | − BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | |
| 257 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 258 | − BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | |
| 259 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 260 | − BIT_ULL(HW_FEATURE_MRT) | \ | |
| 261 | − BIT_ULL(HW_FEATURE_MSAA_16X) | \ | |
| 262 | − BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | |
| 263 | − BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | |
| 264 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 265 | − BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | |
| 266 | 83 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 267 | 84 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ |
| 268 | 85 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ |
| @@ -276,21 +93,6 @@ enum panfrost_hw_feature { · 7 unmodified lines | ||
| 276 | 93 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 277 | 94 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 278 | 95 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 279 | − BIT_ULL(HW_FEATURE_WARPING) | \ | |
| 280 | − BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | |
| 281 | − BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | |
| 282 | − BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | |
| 283 | − BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | |
| 284 | − BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | |
| 285 | − BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | |
| 286 | − BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | |
| 287 | − BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | |
| 288 | − BIT_ULL(HW_FEATURE_MRT) | \ | |
| 289 | − BIT_ULL(HW_FEATURE_MSAA_16X) | \ | |
| 290 | − BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | |
| 291 | − BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | |
| 292 | − BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | |
| 293 | − BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | |
| 294 | 96 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 295 | 97 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ |
| 296 | 98 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ |
| @@ -320,19 +320,36 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev) · 319 unmodified lines | ||
| 320 | 320 | { |
| 321 | 321 | int ret; |
| 322 | 322 | u32 val; |
| 323 | + u64 core_mask = U64_MAX; | |
| 323 | 324 | |
| 324 | 325 | panfrost_gpu_init_quirks(pfdev); |
| 325 | 326 | |
| 326 | − /* Just turn on everything for now */ | |
| 327 | − gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present); | |
| 327 | + if (pfdev->features.l2_present != 1) { | |
| 328 | + /* | |
| 329 | + * Only support one core group now. | |
| 330 | + * ~(l2_present - 1) unsets all bits in l2_present except | |
| 331 | + * the bottom bit. (l2_present - 2) has all the bits in | |
| 332 | + * the first core group set. AND them together to generate | |
| 333 | + * a mask of cores in the first core group. | |
| 334 | + */ | |
| 335 | + core_mask = ~(pfdev->features.l2_present - 1) & | |
| 336 | + (pfdev->features.l2_present - 2); | |
| 337 | + dev_info_once(pfdev->dev, "using only 1st core group (%lu cores from %lu)\n", | |
| 338 | + hweight64(core_mask), | |
| 339 | + hweight64(pfdev->features.shader_present)); | |
| 340 | + } | |
| 341 | + gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present & core_mask); | |
| 328 | 342 | ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO, |
| 329 | − val, val == pfdev->features.l2_present, 100, 20000); | |
| 343 | + val, val == (pfdev->features.l2_present & core_mask), | |
| 344 | + 100, 20000); | |
| 330 | 345 | if (ret) |
| 331 | 346 | dev_err(pfdev->dev, "error powering up gpu L2"); |
| 332 | 347 | |
| 333 | − gpu_write(pfdev, SHADER_PWRON_LO, pfdev->features.shader_present); | |
| 348 | + gpu_write(pfdev, SHADER_PWRON_LO, | |
| 349 | + pfdev->features.shader_present & core_mask); | |
| 334 | 350 | ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO, |
| 335 | − val, val == pfdev->features.shader_present, 100, 20000); | |
| 351 | + val, val == (pfdev->features.shader_present & core_mask), | |
| 352 | + 100, 20000); | |
| 336 | 353 | if (ret) |
| 337 | 354 | dev_err(pfdev->dev, "error powering up gpu shader"); |
| 338 | 355 | |
| @@ -360,8 +377,11 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) · 21 unmodified lines | ||
| 360 | 377 | |
| 361 | 378 | panfrost_gpu_init_features(pfdev); |
| 362 | 379 | |
| 363 | − dma_set_mask_and_coherent(pfdev->dev, | |
| 380 | + err = dma_set_mask_and_coherent(pfdev->dev, | |
| 364 | 381 | DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features))); |
| 382 | + if (err) | |
| 383 | + return err; | |
| 384 | + | |
| 365 | 385 | dma_set_max_seg_size(pfdev->dev, UINT_MAX); |
| 366 | 386 | |
| 367 | 387 | irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | |
| 31 | 31 | #include "atom.h" |
| 32 | 32 | #include "atom-bits.h" |
| 33 | −#include <drm/drm_dp_helper.h> | |
| 33 | +#include <drm/dp/drm_dp_helper.h> | |
| 34 | 34 | |
| 35 | 35 | /* move these to drm_dp_helper.c/h */ |
| 36 | 36 | #define DP_LINK_CONFIGURATION_SIZE 9 |
| @@ -27,7 +27,7 @@ · 26 unmodified lines | ||
| 27 | 27 | #include <drm/drm_edid.h> |
| 28 | 28 | #include <drm/drm_crtc_helper.h> |
| 29 | 29 | #include <drm/drm_fb_helper.h> |
| 30 | −#include <drm/drm_dp_mst_helper.h> | |
| 30 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 31 | 31 | #include <drm/drm_probe_helper.h> |
| 32 | 32 | #include <drm/radeon_drm.h> |
| 33 | 33 | #include "radeon.h" |
| @@ -204,7 +204,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connector) · 170 unmodified lines | ||
| 204 | 204 | |
| 205 | 205 | /* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ |
| 206 | 206 | if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { |
| 207 | − if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) && | |
| 207 | + if ((connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) && | |
| 208 | 208 | (mode_clock * 5/4 <= max_tmds_clock)) |
| 209 | 209 | bpc = 10; |
| 210 | 210 | else |
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: MIT |
| 2 | 2 | |
| 3 | −#include <drm/drm_dp_mst_helper.h> | |
| 3 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 4 | 4 | #include <drm/drm_fb_helper.h> |
| 5 | 5 | #include <drm/drm_file.h> |
| 6 | 6 | #include <drm/drm_probe_helper.h> |
| @@ -33,8 +33,8 @@ · 32 unmodified lines | ||
| 33 | 33 | #include <drm/drm_crtc.h> |
| 34 | 34 | #include <drm/drm_edid.h> |
| 35 | 35 | #include <drm/drm_encoder.h> |
| 36 | −#include <drm/drm_dp_helper.h> | |
| 37 | −#include <drm/drm_dp_mst_helper.h> | |
| 36 | +#include <drm/dp/drm_dp_helper.h> | |
| 37 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 38 | 38 | #include <drm/drm_fixed.h> |
| 39 | 39 | #include <drm/drm_crtc_helper.h> |
| 40 | 40 | #include <linux/i2c.h> |
| @@ -802,7 +802,7 @@ static int radeon_mm_vram_dump_table_show(struct seq_file *m, void *unused) · 801 unmodified lines | ||
| 802 | 802 | TTM_PL_VRAM); |
| 803 | 803 | struct drm_printer p = drm_seq_file_printer(m); |
| 804 | 804 | |
| 805 | − man->func->debug(man, &p); | |
| 805 | + ttm_resource_manager_debug(man, &p); | |
| 806 | 806 | return 0; |
| 807 | 807 | } |
| 808 | 808 | |
| @@ -820,7 +820,7 @@ static int radeon_mm_gtt_dump_table_show(struct seq_file *m, void *unused) · 11 unmodified lines | ||
| 820 | 820 | TTM_PL_TT); |
| 821 | 821 | struct drm_printer p = drm_seq_file_printer(m); |
| 822 | 822 | |
| 823 | − man->func->debug(man, &p); | |
| 823 | + ttm_resource_manager_debug(man, &p); | |
| 824 | 824 | return 0; |
| 825 | 825 | } |
| 826 | 826 | |
| @@ -2,11 +2,13 @@ · 1 unmodified line | ||
| 2 | 2 | config DRM_ROCKCHIP |
| 3 | 3 | tristate "DRM Support for Rockchip" |
| 4 | 4 | depends on DRM && ROCKCHIP_IOMMU |
| 5 | + select DRM_DP_HELPER | |
| 5 | 6 | select DRM_GEM_CMA_HELPER |
| 6 | 7 | select DRM_KMS_HELPER |
| 7 | 8 | select DRM_PANEL |
| 8 | 9 | select VIDEOMODE_HELPERS |
| 9 | 10 | select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP |
| 11 | + select DRM_DP_HELPER if ROCKCHIP_ANALOGIX_DP | |
| 10 | 12 | select DRM_DW_HDMI if ROCKCHIP_DW_HDMI |
| 11 | 13 | select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI |
| 12 | 14 | select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <drm/drm_atomic.h> |
| 23 | 23 | #include <drm/drm_atomic_helper.h> |
| 24 | 24 | #include <drm/bridge/analogix_dp.h> |
| 25 | −#include <drm/drm_dp_helper.h> | |
| 25 | +#include <drm/dp/drm_dp_helper.h> | |
| 26 | 26 | #include <drm/drm_of.h> |
| 27 | 27 | #include <drm/drm_panel.h> |
| 28 | 28 | #include <drm/drm_probe_helper.h> |
| @@ -117,7 +117,7 @@ static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data, · 88 unmodified lines | ||
| 117 | 117 | { |
| 118 | 118 | struct drm_display_info *di = &connector->display_info; |
| 119 | 119 | /* VOP couldn't output YUV video format for eDP rightly */ |
| 120 | − u32 mask = DRM_COLOR_FORMAT_YCRCB444 | DRM_COLOR_FORMAT_YCRCB422; | |
| 120 | + u32 mask = DRM_COLOR_FORMAT_YCBCR444 | DRM_COLOR_FORMAT_YCBCR422; | |
| 121 | 121 | |
| 122 | 122 | if ((di->color_formats & mask)) { |
| 123 | 123 | DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n"); |
| @@ -16,7 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | #include <sound/hdmi-codec.h> |
| 17 | 17 | |
| 18 | 18 | #include <drm/drm_atomic_helper.h> |
| 19 | −#include <drm/drm_dp_helper.h> | |
| 19 | +#include <drm/dp/drm_dp_helper.h> | |
| 20 | 20 | #include <drm/drm_edid.h> |
| 21 | 21 | #include <drm/drm_of.h> |
| 22 | 22 | #include <drm/drm_probe_helper.h> |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | #ifndef _CDN_DP_CORE_H |
| 8 | 8 | #define _CDN_DP_CORE_H |
| 9 | 9 | |
| 10 | −#include <drm/drm_dp_helper.h> | |
| 10 | +#include <drm/dp/drm_dp_helper.h> | |
| 11 | 11 | #include <drm/drm_panel.h> |
| 12 | 12 | #include <drm/drm_probe_helper.h> |
| 13 | 13 | |
| @@ -20,7 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <drm/drm_atomic_helper.h> |
| 21 | 21 | #include <drm/drm_bridge.h> |
| 22 | 22 | #include <drm/drm_bridge_connector.h> |
| 23 | −#include <drm/drm_dp_helper.h> | |
| 23 | +#include <drm/dp/drm_dp_helper.h> | |
| 24 | 24 | #include <drm/drm_of.h> |
| 25 | 25 | #include <drm/drm_panel.h> |
| 26 | 26 | #include <drm/drm_probe_helper.h> |
| @@ -11,7 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <drm/drm_atomic_helper.h> |
| 12 | 12 | #include <drm/drm_bridge.h> |
| 13 | 13 | #include <drm/drm_bridge_connector.h> |
| 14 | −#include <drm/drm_dp_helper.h> | |
| 14 | +#include <drm/dp/drm_dp_helper.h> | |
| 15 | 15 | #include <drm/drm_of.h> |
| 16 | 16 | #include <drm/drm_panel.h> |
| 17 | 17 | #include <drm/drm_probe_helper.h> |
| @@ -7,10 +7,10 @@ · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | #include <linux/random.h> |
| 9 | 9 | |
| 10 | −#include <drm/drm_dp_mst_helper.h> | |
| 10 | +#include <drm/dp/drm_dp_mst_helper.h> | |
| 11 | 11 | #include <drm/drm_print.h> |
| 12 | 12 | |
| 13 | −#include "../drm_dp_mst_topology_internal.h" | |
| 13 | +#include "../dp/drm_dp_mst_topology_internal.h" | |
| 14 | 14 | #include "test-drm_modeset_common.h" |
| 15 | 15 | |
| 16 | 16 | int igt_dp_mst_calc_pbn_mode(void *ignored) |
| @@ -131,8 +131,10 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in) · 114 unmodified lines | ||
| 131 | 131 | return false; |
| 132 | 132 | |
| 133 | 133 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); |
| 134 | − if (!txmsg) | |
| 134 | + if (!txmsg) { | |
| 135 | + kfree(out); | |
| 135 | 136 | return false; |
| 137 | + } | |
| 136 | 138 | |
| 137 | 139 | drm_dp_encode_sideband_req(in, txmsg); |
| 138 | 140 | ret = drm_dp_decode_sideband_req(txmsg, out); |
| @@ -87,11 +87,15 @@ int igt_check_plane_state(void *ignored) · 86 unmodified lines | ||
| 87 | 87 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) |
| 88 | 88 | }, |
| 89 | 89 | }; |
| 90 | + struct drm_plane plane = { | |
| 91 | + .dev = NULL | |
| 92 | + }; | |
| 90 | 93 | struct drm_framebuffer fb = { |
| 91 | 94 | .width = 2048, |
| 92 | 95 | .height = 2048 |
| 93 | 96 | }; |
| 94 | 97 | struct drm_plane_state plane_state = { |
| 98 | + .plane = &plane, | |
| 95 | 99 | .crtc = ZERO_SIZE_PTR, |
| 96 | 100 | .fb = &fb, |
| 97 | 101 | .rotation = DRM_MODE_ROTATE_0 |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/of_platform.h> |
| 15 | 15 | #include <linux/pm_runtime.h> |
| 16 | 16 | |
| 17 | +#include <drm/drm_aperture.h> | |
| 17 | 18 | #include <drm/drm_atomic.h> |
| 18 | 19 | #include <drm/drm_atomic_helper.h> |
| 19 | 20 | #include <drm/drm_drv.h> |
| @@ -183,6 +184,10 @@ static int stm_drm_platform_probe(struct platform_device *pdev) · 163 unmodified lines | ||
| 183 | 184 | |
| 184 | 185 | DRM_DEBUG("%s\n", __func__); |
| 185 | 186 | |
| 187 | + ret = drm_aperture_remove_framebuffers(false, &drv_driver); | |
| 188 | + if (ret) | |
| 189 | + return ret; | |
| 190 | + | |
| 186 | 191 | dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); |
| 187 | 192 | |
| 188 | 193 | ddev = drm_dev_alloc(&drv_driver, dev); |
| @@ -247,14 +247,6 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, · 246 unmodified lines | ||
| 247 | 247 | int ret, bpp; |
| 248 | 248 | u32 val; |
| 249 | 249 | |
| 250 | − /* Update lane capabilities according to hw version */ | |
| 251 | − dsi->lane_min_kbps = LANE_MIN_KBPS; | |
| 252 | − dsi->lane_max_kbps = LANE_MAX_KBPS; | |
| 253 | − if (dsi->hw_version == HWVER_131) { | |
| 254 | − dsi->lane_min_kbps *= 2; | |
| 255 | − dsi->lane_max_kbps *= 2; | |
| 256 | − } | |
| 257 | − | |
| 258 | 250 | pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000); |
| 259 | 251 | |
| 260 | 252 | /* Compute requested pll out */ |
| @@ -330,6 +322,103 @@ dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps, · 69 unmodified lines | ||
| 330 | 322 | return 0; |
| 331 | 323 | } |
| 332 | 324 | |
| 325 | +#define CLK_TOLERANCE_HZ 50 | |
| 326 | + | |
| 327 | +static enum drm_mode_status | |
| 328 | +dw_mipi_dsi_stm_mode_valid(void *priv_data, | |
| 329 | + const struct drm_display_mode *mode, | |
| 330 | + unsigned long mode_flags, u32 lanes, u32 format) | |
| 331 | +{ | |
| 332 | + struct dw_mipi_dsi_stm *dsi = priv_data; | |
| 333 | + unsigned int idf, ndiv, odf, pll_in_khz, pll_out_khz; | |
| 334 | + int ret, bpp; | |
| 335 | + | |
| 336 | + bpp = mipi_dsi_pixel_format_to_bpp(format); | |
| 337 | + if (bpp < 0) | |
| 338 | + return MODE_BAD; | |
| 339 | + | |
| 340 | + /* Compute requested pll out */ | |
| 341 | + pll_out_khz = mode->clock * bpp / lanes; | |
| 342 | + | |
| 343 | + if (pll_out_khz > dsi->lane_max_kbps) | |
| 344 | + return MODE_CLOCK_HIGH; | |
| 345 | + | |
| 346 | + if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { | |
| 347 | + /* Add 20% to pll out to be higher than pixel bw */ | |
| 348 | + pll_out_khz = (pll_out_khz * 12) / 10; | |
| 349 | + } else { | |
| 350 | + if (pll_out_khz < dsi->lane_min_kbps) | |
| 351 | + return MODE_CLOCK_LOW; | |
| 352 | + } | |
| 353 | + | |
| 354 | + /* Compute best pll parameters */ | |
| 355 | + idf = 0; | |
| 356 | + ndiv = 0; | |
| 357 | + odf = 0; | |
| 358 | + pll_in_khz = clk_get_rate(dsi->pllref_clk) / 1000; | |
| 359 | + ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz, &idf, &ndiv, &odf); | |
| 360 | + if (ret) { | |
| 361 | + DRM_WARN("Warning dsi_pll_get_params(): bad params\n"); | |
| 362 | + return MODE_ERROR; | |
| 363 | + } | |
| 364 | + | |
| 365 | + if (!(mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) { | |
| 366 | + unsigned int px_clock_hz, target_px_clock_hz, lane_mbps; | |
| 367 | + int dsi_short_packet_size_px, hfp, hsync, hbp, delay_to_lp; | |
| 368 | + struct dw_mipi_dsi_dphy_timing dphy_timing; | |
| 369 | + | |
| 370 | + /* Get the adjusted pll out value */ | |
| 371 | + pll_out_khz = dsi_pll_get_clkout_khz(pll_in_khz, idf, ndiv, odf); | |
| 372 | + | |
| 373 | + px_clock_hz = DIV_ROUND_CLOSEST_ULL(1000ULL * pll_out_khz * lanes, bpp); | |
| 374 | + target_px_clock_hz = mode->clock * 1000; | |
| 375 | + /* | |
| 376 | + * Filter modes according to the clock value, particularly useful for | |
| 377 | + * hdmi modes that require precise pixel clocks. | |
| 378 | + */ | |
| 379 | + if (px_clock_hz < target_px_clock_hz - CLK_TOLERANCE_HZ || | |
| 380 | + px_clock_hz > target_px_clock_hz + CLK_TOLERANCE_HZ) | |
| 381 | + return MODE_CLOCK_RANGE; | |
| 382 | + | |
| 383 | + /* sync packets are codes as DSI short packets (4 bytes) */ | |
| 384 | + dsi_short_packet_size_px = DIV_ROUND_UP(4 * BITS_PER_BYTE, bpp); | |
| 385 | + | |
| 386 | + hfp = mode->hsync_start - mode->hdisplay; | |
| 387 | + hsync = mode->hsync_end - mode->hsync_start; | |
| 388 | + hbp = mode->htotal - mode->hsync_end; | |
| 389 | + | |
| 390 | + /* hsync must be longer than 4 bytes HSS packets */ | |
| 391 | + if (hsync < dsi_short_packet_size_px) | |
| 392 | + return MODE_HSYNC_NARROW; | |
| 393 | + | |
| 394 | + if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { | |
| 395 | + /* HBP must be longer than 4 bytes HSE packets */ | |
| 396 | + if (hbp < dsi_short_packet_size_px) | |
| 397 | + return MODE_HSYNC_NARROW; | |
| 398 | + hbp -= dsi_short_packet_size_px; | |
| 399 | + } else { | |
| 400 | + /* With sync events HBP extends in the hsync */ | |
| 401 | + hbp += hsync - dsi_short_packet_size_px; | |
| 402 | + } | |
| 403 | + | |
| 404 | + lane_mbps = pll_out_khz / 1000; | |
| 405 | + ret = dw_mipi_dsi_phy_get_timing(priv_data, lane_mbps, &dphy_timing); | |
| 406 | + if (ret) | |
| 407 | + return MODE_ERROR; | |
| 408 | + /* | |
| 409 | + * In non-burst mode DSI has to enter in LP during HFP | |
| 410 | + * (horizontal front porch) or HBP (horizontal back porch) to | |
| 411 | + * resync with LTDC pixel clock. | |
| 412 | + */ | |
| 413 | + delay_to_lp = DIV_ROUND_UP((dphy_timing.data_hs2lp + dphy_timing.data_lp2hs) * | |
| 414 | + lanes * BITS_PER_BYTE, bpp); | |
| 415 | + if (hfp < delay_to_lp && hbp < delay_to_lp) | |
| 416 | + return MODE_HSYNC; | |
| 417 | + } | |
| 418 | + | |
| 419 | + return MODE_OK; | |
| 420 | +} | |
| 421 | + | |
| 333 | 422 | static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { |
| 334 | 423 | .init = dw_mipi_dsi_phy_init, |
| 335 | 424 | .power_on = dw_mipi_dsi_phy_power_on, |
| @@ -340,6 +429,7 @@ static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { · 4 unmodified lines | ||
| 340 | 429 | |
| 341 | 430 | static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data = { |
| 342 | 431 | .max_data_lanes = 2, |
| 432 | + .mode_valid = dw_mipi_dsi_stm_mode_valid, | |
| 343 | 433 | .phy_ops = &dw_mipi_dsi_stm_phy_ops, |
| 344 | 434 | }; |
| 345 | 435 | |
| @@ -417,6 +507,14 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) · 71 unmodified lines | ||
| 417 | 507 | goto err_dsi_probe; |
| 418 | 508 | } |
| 419 | 509 | |
| 510 | + /* set lane capabilities according to hw version */ | |
| 511 | + dsi->lane_min_kbps = LANE_MIN_KBPS; | |
| 512 | + dsi->lane_max_kbps = LANE_MAX_KBPS; | |
| 513 | + if (dsi->hw_version == HWVER_131) { | |
| 514 | + dsi->lane_min_kbps *= 2; | |
| 515 | + dsi->lane_max_kbps *= 2; | |
| 516 | + } | |
| 517 | + | |
| 420 | 518 | dw_mipi_dsi_stm_plat_data.base = dsi->base; |
| 421 | 519 | dw_mipi_dsi_stm_plat_data.priv_data = dsi; |
| 422 | 520 | |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/pinctrl/consumer.h> |
| 19 | 19 | #include <linux/platform_device.h> |
| 20 | 20 | #include <linux/pm_runtime.h> |
| 21 | +#include <linux/regmap.h> | |
| 21 | 22 | #include <linux/reset.h> |
| 22 | 23 | |
| 23 | 24 | #include <drm/drm_atomic.h> |
| @@ -46,15 +47,15 @@ · 22 unmodified lines | ||
| 46 | 47 | #define HWVER_10200 0x010200 |
| 47 | 48 | #define HWVER_10300 0x010300 |
| 48 | 49 | #define HWVER_20101 0x020101 |
| 50 | +#define HWVER_40100 0x040100 | |
| 49 | 51 | |
| 50 | 52 | /* |
| 51 | 53 | * The address of some registers depends on the HW version: such registers have |
| 52 | − * an extra offset specified with reg_ofs. | |
| 54 | + * an extra offset specified with layer_ofs. | |
| 53 | 55 | */ |
| 54 | −#define REG_OFS_NONE 0 | |
| 55 | −#define REG_OFS_4 4 /* Insertion of "Layer Conf. 2" reg */ | |
| 56 | −#define REG_OFS (ldev->caps.reg_ofs) | |
| 57 | −#define LAY_OFS 0x80 /* Register Offset between 2 layers */ | |
| 56 | +#define LAY_OFS_0 0x80 | |
| 57 | +#define LAY_OFS_1 0x100 | |
| 58 | +#define LAY_OFS (ldev->caps.layer_ofs) | |
| 58 | 59 | |
| 59 | 60 | /* Global register offsets */ |
| 60 | 61 | #define LTDC_IDR 0x0000 /* IDentification */ |
| @@ -75,29 +76,35 @@ · 14 unmodified lines | ||
| 75 | 76 | #define LTDC_LIPCR 0x0040 /* Line Interrupt Position Conf. */ |
| 76 | 77 | #define LTDC_CPSR 0x0044 /* Current Position Status */ |
| 77 | 78 | #define LTDC_CDSR 0x0048 /* Current Display Status */ |
| 79 | +#define LTDC_EDCR 0x0060 /* External Display Control */ | |
| 80 | +#define LTDC_FUT 0x0090 /* Fifo underrun Threshold */ | |
| 78 | 81 | |
| 79 | 82 | /* Layer register offsets */ |
| 80 | −#define LTDC_L1LC1R (0x80) /* L1 Layer Configuration 1 */ | |
| 81 | −#define LTDC_L1LC2R (0x84) /* L1 Layer Configuration 2 */ | |
| 82 | −#define LTDC_L1CR (0x84 + REG_OFS)/* L1 Control */ | |
| 83 | −#define LTDC_L1WHPCR (0x88 + REG_OFS)/* L1 Window Hor Position Config */ | |
| 84 | −#define LTDC_L1WVPCR (0x8C + REG_OFS)/* L1 Window Vert Position Config */ | |
| 85 | −#define LTDC_L1CKCR (0x90 + REG_OFS)/* L1 Color Keying Configuration */ | |
| 86 | −#define LTDC_L1PFCR (0x94 + REG_OFS)/* L1 Pixel Format Configuration */ | |
| 87 | −#define LTDC_L1CACR (0x98 + REG_OFS)/* L1 Constant Alpha Config */ | |
| 88 | −#define LTDC_L1DCCR (0x9C + REG_OFS)/* L1 Default Color Configuration */ | |
| 89 | −#define LTDC_L1BFCR (0xA0 + REG_OFS)/* L1 Blend Factors Configuration */ | |
| 90 | −#define LTDC_L1FBBCR (0xA4 + REG_OFS)/* L1 FrameBuffer Bus Control */ | |
| 91 | −#define LTDC_L1AFBCR (0xA8 + REG_OFS)/* L1 AuxFB Control */ | |
| 92 | −#define LTDC_L1CFBAR (0xAC + REG_OFS)/* L1 Color FrameBuffer Address */ | |
| 93 | −#define LTDC_L1CFBLR (0xB0 + REG_OFS)/* L1 Color FrameBuffer Length */ | |
| 94 | −#define LTDC_L1CFBLNR (0xB4 + REG_OFS)/* L1 Color FrameBuffer Line Nb */ | |
| 95 | −#define LTDC_L1AFBAR (0xB8 + REG_OFS)/* L1 AuxFB Address */ | |
| 96 | −#define LTDC_L1AFBLR (0xBC + REG_OFS)/* L1 AuxFB Length */ | |
| 97 | −#define LTDC_L1AFBLNR (0xC0 + REG_OFS)/* L1 AuxFB Line Number */ | |
| 98 | −#define LTDC_L1CLUTWR (0xC4 + REG_OFS)/* L1 CLUT Write */ | |
| 99 | −#define LTDC_L1YS1R (0xE0 + REG_OFS)/* L1 YCbCr Scale 1 */ | |
| 100 | −#define LTDC_L1YS2R (0xE4 + REG_OFS)/* L1 YCbCr Scale 2 */ | |
| 83 | +#define LTDC_L1C0R (ldev->caps.layer_regs[0]) /* L1 configuration 0 */ | |
| 84 | +#define LTDC_L1C1R (ldev->caps.layer_regs[1]) /* L1 configuration 1 */ | |
| 85 | +#define LTDC_L1RCR (ldev->caps.layer_regs[2]) /* L1 reload control */ | |
| 86 | +#define LTDC_L1CR (ldev->caps.layer_regs[3]) /* L1 control register */ | |
| 87 | +#define LTDC_L1WHPCR (ldev->caps.layer_regs[4]) /* L1 window horizontal position configuration */ | |
| 88 | +#define LTDC_L1WVPCR (ldev->caps.layer_regs[5]) /* L1 window vertical position configuration */ | |
| 89 | +#define LTDC_L1CKCR (ldev->caps.layer_regs[6]) /* L1 color keying configuration */ | |
| 90 | +#define LTDC_L1PFCR (ldev->caps.layer_regs[7]) /* L1 pixel format configuration */ | |
| 91 | +#define LTDC_L1CACR (ldev->caps.layer_regs[8]) /* L1 constant alpha configuration */ | |
| 92 | +#define LTDC_L1DCCR (ldev->caps.layer_regs[9]) /* L1 default color configuration */ | |
| 93 | +#define LTDC_L1BFCR (ldev->caps.layer_regs[10]) /* L1 blending factors configuration */ | |
| 94 | +#define LTDC_L1BLCR (ldev->caps.layer_regs[11]) /* L1 burst length configuration */ | |
| 95 | +#define LTDC_L1PCR (ldev->caps.layer_regs[12]) /* L1 planar configuration */ | |
| 96 | +#define LTDC_L1CFBAR (ldev->caps.layer_regs[13]) /* L1 color frame buffer address */ | |
| 97 | +#define LTDC_L1CFBLR (ldev->caps.layer_regs[14]) /* L1 color frame buffer length */ | |
| 98 | +#define LTDC_L1CFBLNR (ldev->caps.layer_regs[15]) /* L1 color frame buffer line number */ | |
| 99 | +#define LTDC_L1AFBA0R (ldev->caps.layer_regs[16]) /* L1 auxiliary frame buffer address 0 */ | |
| 100 | +#define LTDC_L1AFBA1R (ldev->caps.layer_regs[17]) /* L1 auxiliary frame buffer address 1 */ | |
| 101 | +#define LTDC_L1AFBLR (ldev->caps.layer_regs[18]) /* L1 auxiliary frame buffer length */ | |
| 102 | +#define LTDC_L1AFBLNR (ldev->caps.layer_regs[19]) /* L1 auxiliary frame buffer line number */ | |
| 103 | +#define LTDC_L1CLUTWR (ldev->caps.layer_regs[20]) /* L1 CLUT write */ | |
| 104 | +#define LTDC_L1CYR0R (ldev->caps.layer_regs[21]) /* L1 Conversion YCbCr RGB 0 */ | |
| 105 | +#define LTDC_L1CYR1R (ldev->caps.layer_regs[22]) /* L1 Conversion YCbCr RGB 1 */ | |
| 106 | +#define LTDC_L1FPF0R (ldev->caps.layer_regs[23]) /* L1 Flexible Pixel Format 0 */ | |
| 107 | +#define LTDC_L1FPF1R (ldev->caps.layer_regs[24]) /* L1 Flexible Pixel Format 1 */ | |
| 101 | 108 | |
| 102 | 109 | /* Bit definitions */ |
| 103 | 110 | #define SSCR_VSH GENMASK(10, 0) /* Vertical Synchronization Height */ |
| @@ -164,6 +171,10 @@ · 60 unmodified lines | ||
| 164 | 171 | #define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */ |
| 165 | 172 | #define ISR_RRIF BIT(3) /* Register Reload Interrupt Flag */ |
| 166 | 173 | |
| 174 | +#define EDCR_OCYEN BIT(25) /* Output Conversion to YCbCr 422: ENable */ | |
| 175 | +#define EDCR_OCYSEL BIT(26) /* Output Conversion to YCbCr 422: SELection of the CCIR */ | |
| 176 | +#define EDCR_OCYCO BIT(27) /* Output Conversion to YCbCr 422: Chrominance Order */ | |
| 177 | + | |
| 167 | 178 | #define LXCR_LEN BIT(0) /* Layer ENable */ |
| 168 | 179 | #define LXCR_COLKEN BIT(1) /* Color Keying Enable */ |
| 169 | 180 | #define LXCR_CLUTEN BIT(4) /* Color Look-Up Table ENable */ |
| @@ -175,6 +186,7 @@ · 5 unmodified lines | ||
| 175 | 186 | #define LXWVPCR_WVSPPOS GENMASK(26, 16) /* Window Vertical StoP POSition */ |
| 176 | 187 | |
| 177 | 188 | #define LXPFCR_PF GENMASK(2, 0) /* Pixel Format */ |
| 189 | +#define PF_FLEXIBLE 0x7 /* Flexible Pixel Format selected */ | |
| 178 | 190 | |
| 179 | 191 | #define LXCACR_CONSTA GENMASK(7, 0) /* CONSTant Alpha */ |
| 180 | 192 | |
| @@ -186,6 +198,25 @@ · 5 unmodified lines | ||
| 186 | 198 | |
| 187 | 199 | #define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */ |
| 188 | 200 | |
| 201 | +#define LXCR_C1R_YIA BIT(0) /* Ycbcr 422 Interleaved Ability */ | |
| 202 | +#define LXCR_C1R_YSPA BIT(1) /* Ycbcr 420 Semi-Planar Ability */ | |
| 203 | +#define LXCR_C1R_YFPA BIT(2) /* Ycbcr 420 Full-Planar Ability */ | |
| 204 | +#define LXCR_C1R_SCA BIT(31) /* SCaling Ability*/ | |
| 205 | + | |
| 206 | +#define LxPCR_YREN BIT(9) /* Y Rescale Enable for the color dynamic range */ | |
| 207 | +#define LxPCR_OF BIT(8) /* Odd pixel First */ | |
| 208 | +#define LxPCR_CBF BIT(7) /* CB component First */ | |
| 209 | +#define LxPCR_YF BIT(6) /* Y component First */ | |
| 210 | +#define LxPCR_YCM GENMASK(5, 4) /* Ycbcr Conversion Mode */ | |
| 211 | +#define YCM_I 0x0 /* Interleaved 422 */ | |
| 212 | +#define YCM_SP 0x1 /* Semi-Planar 420 */ | |
| 213 | +#define YCM_FP 0x2 /* Full-Planar 420 */ | |
| 214 | +#define LxPCR_YCEN BIT(3) /* YCbCr-to-RGB Conversion Enable */ | |
| 215 | + | |
| 216 | +#define LXRCR_IMR BIT(0) /* IMmediate Reload */ | |
| 217 | +#define LXRCR_VBR BIT(1) /* Vertical Blanking Reload */ | |
| 218 | +#define LXRCR_GRMSK BIT(2) /* Global (centralized) Reload MaSKed */ | |
| 219 | + | |
| 189 | 220 | #define CLUT_SIZE 256 |
| 190 | 221 | |
| 191 | 222 | #define CONSTA_MAX 0xFF /* CONSTant Alpha MAX= 1.0 */ |
| @@ -201,8 +232,12 @@ enum ltdc_pix_fmt { · 9 unmodified lines | ||
| 201 | 232 | /* RGB formats */ |
| 202 | 233 | PF_ARGB8888, /* ARGB [32 bits] */ |
| 203 | 234 | PF_RGBA8888, /* RGBA [32 bits] */ |
| 235 | + PF_ABGR8888, /* ABGR [32 bits] */ | |
| 236 | + PF_BGRA8888, /* BGRA [32 bits] */ | |
| 204 | 237 | PF_RGB888, /* RGB [24 bits] */ |
| 238 | + PF_BGR888, /* BGR [24 bits] */ | |
| 205 | 239 | PF_RGB565, /* RGB [16 bits] */ |
| 240 | + PF_BGR565, /* BGR [16 bits] */ | |
| 206 | 241 | PF_ARGB1555, /* ARGB A:1 bit RGB:15 bits [16 bits] */ |
| 207 | 242 | PF_ARGB4444, /* ARGB A:4 bits R/G/B: 4 bits each [16 bits] */ |
| 208 | 243 | /* Indexed formats */ |
| @@ -234,36 +269,198 @@ static const enum ltdc_pix_fmt ltdc_pix_fmt_a1[NB_PF] = { · 25 unmodified lines | ||
| 234 | 269 | PF_ARGB4444 /* 0x07 */ |
| 235 | 270 | }; |
| 236 | 271 | |
| 237 | −static const u64 ltdc_format_modifiers[] = { | |
| 238 | − DRM_FORMAT_MOD_LINEAR, | |
| 239 | − DRM_FORMAT_MOD_INVALID | |
| 272 | +static const enum ltdc_pix_fmt ltdc_pix_fmt_a2[NB_PF] = { | |
| 273 | + PF_ARGB8888, /* 0x00 */ | |
| 274 | + PF_ABGR8888, /* 0x01 */ | |
| 275 | + PF_RGBA8888, /* 0x02 */ | |
| 276 | + PF_BGRA8888, /* 0x03 */ | |
| 277 | + PF_RGB565, /* 0x04 */ | |
| 278 | + PF_BGR565, /* 0x05 */ | |
| 279 | + PF_RGB888, /* 0x06 */ | |
| 280 | + PF_NONE /* 0x07 */ | |
| 240 | 281 | }; |
| 241 | 282 | |
| 242 | −static inline u32 reg_read(void __iomem *base, u32 reg) | |
| 243 | −{ | |
| 244 | − return readl_relaxed(base + reg); | |
| 245 | −} | |
| 283 | +static const u32 ltdc_drm_fmt_a0[] = { | |
| 284 | + DRM_FORMAT_ARGB8888, | |
| 285 | + DRM_FORMAT_XRGB8888, | |
| 286 | + DRM_FORMAT_RGB888, | |
| 287 | + DRM_FORMAT_RGB565, | |
| 288 | + DRM_FORMAT_ARGB1555, | |
| 289 | + DRM_FORMAT_XRGB1555, | |
| 290 | + DRM_FORMAT_ARGB4444, | |
| 291 | + DRM_FORMAT_XRGB4444, | |
| 292 | + DRM_FORMAT_C8 | |
| 293 | +}; | |
| 246 | 294 | |
| 247 | −static inline void reg_write(void __iomem *base, u32 reg, u32 val) | |
| 248 | −{ | |
| 249 | − writel_relaxed(val, base + reg); | |
| 250 | −} | |
| 295 | +static const u32 ltdc_drm_fmt_a1[] = { | |
| 296 | + DRM_FORMAT_ARGB8888, | |
| 297 | + DRM_FORMAT_XRGB8888, | |
| 298 | + DRM_FORMAT_RGB888, | |
| 299 | + DRM_FORMAT_RGB565, | |
| 300 | + DRM_FORMAT_RGBA8888, | |
| 301 | + DRM_FORMAT_RGBX8888, | |
| 302 | + DRM_FORMAT_ARGB1555, | |
| 303 | + DRM_FORMAT_XRGB1555, | |
| 304 | + DRM_FORMAT_ARGB4444, | |
| 305 | + DRM_FORMAT_XRGB4444, | |
| 306 | + DRM_FORMAT_C8 | |
| 307 | +}; | |
| 251 | 308 | |
| 252 | −static inline void reg_set(void __iomem *base, u32 reg, u32 mask) | |
| 253 | −{ | |
| 254 | − reg_write(base, reg, reg_read(base, reg) | mask); | |
| 255 | −} | |
| 309 | +static const u32 ltdc_drm_fmt_a2[] = { | |
| 310 | + DRM_FORMAT_ARGB8888, | |
| 311 | + DRM_FORMAT_XRGB8888, | |
| 312 | + DRM_FORMAT_ABGR8888, | |
| 313 | + DRM_FORMAT_XBGR8888, | |
| 314 | + DRM_FORMAT_RGBA8888, | |
| 315 | + DRM_FORMAT_RGBX8888, | |
| 316 | + DRM_FORMAT_BGRA8888, | |
| 317 | + DRM_FORMAT_BGRX8888, | |
| 318 | + DRM_FORMAT_RGB565, | |
| 319 | + DRM_FORMAT_BGR565, | |
| 320 | + DRM_FORMAT_RGB888, | |
| 321 | + DRM_FORMAT_BGR888, | |
| 322 | + DRM_FORMAT_ARGB1555, | |
| 323 | + DRM_FORMAT_XRGB1555, | |
| 324 | + DRM_FORMAT_ARGB4444, | |
| 325 | + DRM_FORMAT_XRGB4444, | |
| 326 | + DRM_FORMAT_C8 | |
| 327 | +}; | |
| 256 | 328 | |
| 257 | −static inline void reg_clear(void __iomem *base, u32 reg, u32 mask) | |
| 258 | −{ | |
| 259 | − reg_write(base, reg, reg_read(base, reg) & ~mask); | |
| 260 | −} | |
| 329 | +static const u32 ltdc_drm_fmt_ycbcr_cp[] = { | |
| 330 | + DRM_FORMAT_YUYV, | |
| 331 | + DRM_FORMAT_YVYU, | |
| 332 | + DRM_FORMAT_UYVY, | |
| 333 | + DRM_FORMAT_VYUY | |
| 334 | +}; | |
| 261 | 335 | |
| 262 | −static inline void reg_update_bits(void __iomem *base, u32 reg, u32 mask, | |
| 263 | − u32 val) | |
| 264 | −{ | |
| 265 | − reg_write(base, reg, (reg_read(base, reg) & ~mask) | val); | |
| 266 | −} | |
| 336 | +static const u32 ltdc_drm_fmt_ycbcr_sp[] = { | |
| 337 | + DRM_FORMAT_NV12, | |
| 338 | + DRM_FORMAT_NV21 | |
| 339 | +}; | |
| 340 | + | |
| 341 | +static const u32 ltdc_drm_fmt_ycbcr_fp[] = { | |
| 342 | + DRM_FORMAT_YUV420, | |
| 343 | + DRM_FORMAT_YVU420 | |
| 344 | +}; | |
| 345 | + | |
| 346 | +/* Layer register offsets */ | |
| 347 | +static const u32 ltdc_layer_regs_a0[] = { | |
| 348 | + 0x80, /* L1 configuration 0 */ | |
| 349 | + 0x00, /* not available */ | |
| 350 | + 0x00, /* not available */ | |
| 351 | + 0x84, /* L1 control register */ | |
| 352 | + 0x88, /* L1 window horizontal position configuration */ | |
| 353 | + 0x8c, /* L1 window vertical position configuration */ | |
| 354 | + 0x90, /* L1 color keying configuration */ | |
| 355 | + 0x94, /* L1 pixel format configuration */ | |
| 356 | + 0x98, /* L1 constant alpha configuration */ | |
| 357 | + 0x9c, /* L1 default color configuration */ | |
| 358 | + 0xa0, /* L1 blending factors configuration */ | |
| 359 | + 0x00, /* not available */ | |
| 360 | + 0x00, /* not available */ | |
| 361 | + 0xac, /* L1 color frame buffer address */ | |
| 362 | + 0xb0, /* L1 color frame buffer length */ | |
| 363 | + 0xb4, /* L1 color frame buffer line number */ | |
| 364 | + 0x00, /* not available */ | |
| 365 | + 0x00, /* not available */ | |
| 366 | + 0x00, /* not available */ | |
| 367 | + 0x00, /* not available */ | |
| 368 | + 0xc4, /* L1 CLUT write */ | |
| 369 | + 0x00, /* not available */ | |
| 370 | + 0x00, /* not available */ | |
| 371 | + 0x00, /* not available */ | |
| 372 | + 0x00 /* not available */ | |
| 373 | +}; | |
| 374 | + | |
| 375 | +static const u32 ltdc_layer_regs_a1[] = { | |
| 376 | + 0x80, /* L1 configuration 0 */ | |
| 377 | + 0x84, /* L1 configuration 1 */ | |
| 378 | + 0x00, /* L1 reload control */ | |
| 379 | + 0x88, /* L1 control register */ | |
| 380 | + 0x8c, /* L1 window horizontal position configuration */ | |
| 381 | + 0x90, /* L1 window vertical position configuration */ | |
| 382 | + 0x94, /* L1 color keying configuration */ | |
| 383 | + 0x98, /* L1 pixel format configuration */ | |
| 384 | + 0x9c, /* L1 constant alpha configuration */ | |
| 385 | + 0xa0, /* L1 default color configuration */ | |
| 386 | + 0xa4, /* L1 blending factors configuration */ | |
| 387 | + 0xa8, /* L1 burst length configuration */ | |
| 388 | + 0x00, /* not available */ | |
| 389 | + 0xac, /* L1 color frame buffer address */ | |
| 390 | + 0xb0, /* L1 color frame buffer length */ | |
| 391 | + 0xb4, /* L1 color frame buffer line number */ | |
| 392 | + 0xb8, /* L1 auxiliary frame buffer address 0 */ | |
| 393 | + 0xbc, /* L1 auxiliary frame buffer address 1 */ | |
| 394 | + 0xc0, /* L1 auxiliary frame buffer length */ | |
| 395 | + 0xc4, /* L1 auxiliary frame buffer line number */ | |
| 396 | + 0xc8, /* L1 CLUT write */ | |
| 397 | + 0x00, /* not available */ | |
| 398 | + 0x00, /* not available */ | |
| 399 | + 0x00, /* not available */ | |
| 400 | + 0x00 /* not available */ | |
| 401 | +}; | |
| 402 | + | |
| 403 | +static const u32 ltdc_layer_regs_a2[] = { | |
| 404 | + 0x100, /* L1 configuration 0 */ | |
| 405 | + 0x104, /* L1 configuration 1 */ | |
| 406 | + 0x108, /* L1 reload control */ | |
| 407 | + 0x10c, /* L1 control register */ | |
| 408 | + 0x110, /* L1 window horizontal position configuration */ | |
| 409 | + 0x114, /* L1 window vertical position configuration */ | |
| 410 | + 0x118, /* L1 color keying configuration */ | |
| 411 | + 0x11c, /* L1 pixel format configuration */ | |
| 412 | + 0x120, /* L1 constant alpha configuration */ | |
| 413 | + 0x124, /* L1 default color configuration */ | |
| 414 | + 0x128, /* L1 blending factors configuration */ | |
| 415 | + 0x12c, /* L1 burst length configuration */ | |
| 416 | + 0x130, /* L1 planar configuration */ | |
| 417 | + 0x134, /* L1 color frame buffer address */ | |
| 418 | + 0x138, /* L1 color frame buffer length */ | |
| 419 | + 0x13c, /* L1 color frame buffer line number */ | |
| 420 | + 0x140, /* L1 auxiliary frame buffer address 0 */ | |
| 421 | + 0x144, /* L1 auxiliary frame buffer address 1 */ | |
| 422 | + 0x148, /* L1 auxiliary frame buffer length */ | |
| 423 | + 0x14c, /* L1 auxiliary frame buffer line number */ | |
| 424 | + 0x150, /* L1 CLUT write */ | |
| 425 | + 0x16c, /* L1 Conversion YCbCr RGB 0 */ | |
| 426 | + 0x170, /* L1 Conversion YCbCr RGB 1 */ | |
| 427 | + 0x174, /* L1 Flexible Pixel Format 0 */ | |
| 428 | + 0x178 /* L1 Flexible Pixel Format 1 */ | |
| 429 | +}; | |
| 430 | + | |
| 431 | +static const u64 ltdc_format_modifiers[] = { | |
| 432 | + DRM_FORMAT_MOD_LINEAR, | |
| 433 | + DRM_FORMAT_MOD_INVALID | |
| 434 | +}; | |
| 435 | + | |
| 436 | +static const struct regmap_config stm32_ltdc_regmap_cfg = { | |
| 437 | + .reg_bits = 32, | |
| 438 | + .val_bits = 32, | |
| 439 | + .reg_stride = sizeof(u32), | |
| 440 | + .max_register = 0x400, | |
| 441 | + .use_relaxed_mmio = true, | |
| 442 | + .cache_type = REGCACHE_NONE, | |
| 443 | +}; | |
| 444 | + | |
| 445 | +static const u32 ltdc_ycbcr2rgb_coeffs[DRM_COLOR_ENCODING_MAX][DRM_COLOR_RANGE_MAX][2] = { | |
| 446 | + [DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_LIMITED_RANGE] = { | |
| 447 | + 0x02040199, /* (b_cb = 516 / r_cr = 409) */ | |
| 448 | + 0x006400D0 /* (g_cb = 100 / g_cr = 208) */ | |
| 449 | + }, | |
| 450 | + [DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_FULL_RANGE] = { | |
| 451 | + 0x01C60167, /* (b_cb = 454 / r_cr = 359) */ | |
| 452 | + 0x005800B7 /* (g_cb = 88 / g_cr = 183) */ | |
| 453 | + }, | |
| 454 | + [DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE] = { | |
| 455 | + 0x021D01CB, /* (b_cb = 541 / r_cr = 459) */ | |
| 456 | + 0x00370089 /* (g_cb = 55 / g_cr = 137) */ | |
| 457 | + }, | |
| 458 | + [DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_FULL_RANGE] = { | |
| 459 | + 0x01DB0193, /* (b_cb = 475 / r_cr = 403) */ | |
| 460 | + 0x00300078 /* (g_cb = 48 / g_cr = 120) */ | |
| 461 | + } | |
| 462 | + /* BT2020 not supported */ | |
| 463 | +}; | |
| 267 | 464 | |
| 268 | 465 | static inline struct ltdc_device *crtc_to_ltdc(struct drm_crtc *crtc) |
| 269 | 466 | { |
| @@ -289,16 +486,30 @@ static inline enum ltdc_pix_fmt to_ltdc_pixelformat(u32 drm_fmt) · 19 unmodified lines | ||
| 289 | 486 | case DRM_FORMAT_XRGB8888: |
| 290 | 487 | pf = PF_ARGB8888; |
| 291 | 488 | break; |
| 489 | + case DRM_FORMAT_ABGR8888: | |
| 490 | + case DRM_FORMAT_XBGR8888: | |
| 491 | + pf = PF_ABGR8888; | |
| 492 | + break; | |
| 292 | 493 | case DRM_FORMAT_RGBA8888: |
| 293 | 494 | case DRM_FORMAT_RGBX8888: |
| 294 | 495 | pf = PF_RGBA8888; |
| 295 | 496 | break; |
| 497 | + case DRM_FORMAT_BGRA8888: | |
| 498 | + case DRM_FORMAT_BGRX8888: | |
| 499 | + pf = PF_BGRA8888; | |
| 500 | + break; | |
| 296 | 501 | case DRM_FORMAT_RGB888: |
| 297 | 502 | pf = PF_RGB888; |
| 298 | 503 | break; |
| 504 | + case DRM_FORMAT_BGR888: | |
| 505 | + pf = PF_BGR888; | |
| 506 | + break; | |
| 299 | 507 | case DRM_FORMAT_RGB565: |
| 300 | 508 | pf = PF_RGB565; |
| 301 | 509 | break; |
| 510 | + case DRM_FORMAT_BGR565: | |
| 511 | + pf = PF_BGR565; | |
| 512 | + break; | |
| 302 | 513 | case DRM_FORMAT_ARGB1555: |
| 303 | 514 | case DRM_FORMAT_XRGB1555: |
| 304 | 515 | pf = PF_ARGB1555; |
| @@ -319,49 +530,138 @@ static inline enum ltdc_pix_fmt to_ltdc_pixelformat(u32 drm_fmt) · 14 unmodified lines | ||
| 319 | 530 | return pf; |
| 320 | 531 | } |
| 321 | 532 | |
| 322 | −static inline u32 to_drm_pixelformat(enum ltdc_pix_fmt pf) | |
| 533 | +static inline u32 ltdc_set_flexible_pixel_format(struct drm_plane *plane, enum ltdc_pix_fmt pix_fmt) | |
| 323 | 534 | { |
| 324 | − switch (pf) { | |
| 325 | − case PF_ARGB8888: | |
| 326 | − return DRM_FORMAT_ARGB8888; | |
| 327 | − case PF_RGBA8888: | |
| 328 | − return DRM_FORMAT_RGBA8888; | |
| 329 | − case PF_RGB888: | |
| 330 | − return DRM_FORMAT_RGB888; | |
| 331 | − case PF_RGB565: | |
| 332 | − return DRM_FORMAT_RGB565; | |
| 535 | + struct ltdc_device *ldev = plane_to_ltdc(plane); | |
| 536 | + u32 lofs = plane->index * LAY_OFS, ret = PF_FLEXIBLE; | |
| 537 | + int psize, alen, apos, rlen, rpos, glen, gpos, blen, bpos; | |
| 538 | + | |
| 539 | + switch (pix_fmt) { | |
| 540 | + case PF_BGR888: | |
| 541 | + psize = 3; | |
| 542 | + alen = 0; apos = 0; rlen = 8; rpos = 0; | |
| 543 | + glen = 8; gpos = 8; blen = 8; bpos = 16; | |
| 544 | + break; | |
| 333 | 545 | case PF_ARGB1555: |
| 334 | − return DRM_FORMAT_ARGB1555; | |
| 546 | + psize = 2; | |
| 547 | + alen = 1; apos = 15; rlen = 5; rpos = 10; | |
| 548 | + glen = 5; gpos = 5; blen = 5; bpos = 0; | |
| 549 | + break; | |
| 335 | 550 | case PF_ARGB4444: |
| 336 | − return DRM_FORMAT_ARGB4444; | |
| 551 | + psize = 2; | |
| 552 | + alen = 4; apos = 12; rlen = 4; rpos = 8; | |
| 553 | + glen = 4; gpos = 4; blen = 4; bpos = 0; | |
| 554 | + break; | |
| 337 | 555 | case PF_L8: |
| 338 | − return DRM_FORMAT_C8; | |
| 339 | − case PF_AL44: /* No DRM support */ | |
| 340 | − case PF_AL88: /* No DRM support */ | |
| 341 | − case PF_NONE: | |
| 556 | + psize = 1; | |
| 557 | + alen = 0; apos = 0; rlen = 8; rpos = 0; | |
| 558 | + glen = 8; gpos = 0; blen = 8; bpos = 0; | |
| 559 | + break; | |
| 560 | + case PF_AL44: | |
| 561 | + psize = 1; | |
| 562 | + alen = 4; apos = 4; rlen = 4; rpos = 0; | |
| 563 | + glen = 4; gpos = 0; blen = 4; bpos = 0; | |
| 564 | + break; | |
| 565 | + case PF_AL88: | |
| 566 | + psize = 2; | |
| 567 | + alen = 8; apos = 8; rlen = 8; rpos = 0; | |
| 568 | + glen = 8; gpos = 0; blen = 8; bpos = 0; | |
| 569 | + break; | |
| 342 | 570 | default: |
| 343 | − return 0; | |
| 571 | + ret = NB_PF; /* error case, trace msg is handled by the caller */ | |
| 572 | + break; | |
| 344 | 573 | } |
| 574 | + | |
| 575 | + if (ret == PF_FLEXIBLE) { | |
| 576 | + regmap_write(ldev->regmap, LTDC_L1FPF0R + lofs, | |
| 577 | + (rlen << 14) + (rpos << 9) + (alen << 5) + apos); | |
| 578 | + | |
| 579 | + regmap_write(ldev->regmap, LTDC_L1FPF1R + lofs, | |
| 580 | + (psize << 18) + (blen << 14) + (bpos << 9) + (glen << 5) + gpos); | |
| 581 | + } | |
| 582 | + | |
| 583 | + return ret; | |
| 345 | 584 | } |
| 346 | 585 | |
| 347 | −static inline u32 get_pixelformat_without_alpha(u32 drm) | |
| 586 | +/* | |
| 587 | + * All non-alpha color formats derived from native alpha color formats are | |
| 588 | + * either characterized by a FourCC format code | |
| 589 | + */ | |
| 590 | +static inline u32 is_xrgb(u32 drm) | |
| 348 | 591 | { |
| 349 | − switch (drm) { | |
| 350 | − case DRM_FORMAT_ARGB4444: | |
| 351 | − return DRM_FORMAT_XRGB4444; | |
| 352 | − case DRM_FORMAT_RGBA4444: | |
| 353 | − return DRM_FORMAT_RGBX4444; | |
| 354 | − case DRM_FORMAT_ARGB1555: | |
| 355 | − return DRM_FORMAT_XRGB1555; | |
| 356 | − case DRM_FORMAT_RGBA5551: | |
| 357 | − return DRM_FORMAT_RGBX5551; | |
| 358 | − case DRM_FORMAT_ARGB8888: | |
| 359 | − return DRM_FORMAT_XRGB8888; | |
| 360 | − case DRM_FORMAT_RGBA8888: | |
| 361 | − return DRM_FORMAT_RGBX8888; | |
| 592 | + return ((drm & 0xFF) == 'X' || ((drm >> 8) & 0xFF) == 'X'); | |
| 593 | +} | |
| 594 | + | |
| 595 | +static inline void ltdc_set_ycbcr_config(struct drm_plane *plane, u32 drm_pix_fmt) | |
| 596 | +{ | |
| 597 | + struct ltdc_device *ldev = plane_to_ltdc(plane); | |
| 598 | + struct drm_plane_state *state = plane->state; | |
| 599 | + u32 lofs = plane->index * LAY_OFS; | |
| 600 | + u32 val; | |
| 601 | + | |
| 602 | + switch (drm_pix_fmt) { | |
| 603 | + case DRM_FORMAT_YUYV: | |
| 604 | + val = (YCM_I << 4) | LxPCR_YF | LxPCR_CBF; | |
| 605 | + break; | |
| 606 | + case DRM_FORMAT_YVYU: | |
| 607 | + val = (YCM_I << 4) | LxPCR_YF; | |
| 608 | + break; | |
| 609 | + case DRM_FORMAT_UYVY: | |
| 610 | + val = (YCM_I << 4) | LxPCR_CBF; | |
| 611 | + break; | |
| 612 | + case DRM_FORMAT_VYUY: | |
| 613 | + val = (YCM_I << 4); | |
| 614 | + break; | |
| 615 | + case DRM_FORMAT_NV12: | |
| 616 | + val = (YCM_SP << 4) | LxPCR_CBF; | |
| 617 | + break; | |
| 618 | + case DRM_FORMAT_NV21: | |
| 619 | + val = (YCM_SP << 4); | |
| 620 | + break; | |
| 621 | + case DRM_FORMAT_YUV420: | |
| 622 | + case DRM_FORMAT_YVU420: | |
| 623 | + val = (YCM_FP << 4); | |
| 624 | + break; | |
| 362 | 625 | default: |
| 363 | − return 0; | |
| 626 | + /* RGB or not a YCbCr supported format */ | |
| 627 | + break; | |
| 628 | + } | |
| 629 | + | |
| 630 | + /* Enable limited range */ | |
| 631 | + if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) | |
| 632 | + val |= LxPCR_YREN; | |
| 633 | + | |
| 634 | + /* enable ycbcr conversion */ | |
| 635 | + val |= LxPCR_YCEN; | |
| 636 | + | |
| 637 | + regmap_write(ldev->regmap, LTDC_L1PCR + lofs, val); | |
| 638 | +} | |
| 639 | + | |
| 640 | +static inline void ltdc_set_ycbcr_coeffs(struct drm_plane *plane) | |
| 641 | +{ | |
| 642 | + struct ltdc_device *ldev = plane_to_ltdc(plane); | |
| 643 | + struct drm_plane_state *state = plane->state; | |
| 644 | + enum drm_color_encoding enc = state->color_encoding; | |
| 645 | + enum drm_color_range ran = state->color_range; | |
| 646 | + u32 lofs = plane->index * LAY_OFS; | |
| 647 | + | |
| 648 | + if (enc != DRM_COLOR_YCBCR_BT601 && enc != DRM_COLOR_YCBCR_BT709) { | |
| 649 | + DRM_ERROR("color encoding %d not supported, use bt601 by default\n", enc); | |
| 650 | + /* set by default color encoding to DRM_COLOR_YCBCR_BT601 */ | |
| 651 | + enc = DRM_COLOR_YCBCR_BT601; | |
| 652 | + } | |
| 653 | + | |
| 654 | + if (ran != DRM_COLOR_YCBCR_LIMITED_RANGE && ran != DRM_COLOR_YCBCR_FULL_RANGE) { | |
| 655 | + DRM_ERROR("color range %d not supported, use limited range by default\n", ran); | |
| 656 | + /* set by default color range to DRM_COLOR_YCBCR_LIMITED_RANGE */ | |
| 657 | + ran = DRM_COLOR_YCBCR_LIMITED_RANGE; | |
| 364 | 658 | } |
| 659 | + | |
| 660 | + DRM_DEBUG_DRIVER("Color encoding=%d, range=%d\n", enc, ran); | |
| 661 | + regmap_write(ldev->regmap, LTDC_L1CYR0R + lofs, | |
| 662 | + ltdc_ycbcr2rgb_coeffs[enc][ran][0]); | |
| 663 | + regmap_write(ldev->regmap, LTDC_L1CYR1R + lofs, | |
| 664 | + ltdc_ycbcr2rgb_coeffs[enc][ran][1]); | |
| 365 | 665 | } |
| 366 | 666 | |
| 367 | 667 | static irqreturn_t ltdc_irq_thread(int irq, void *arg) |
| @@ -390,9 +690,13 @@ static irqreturn_t ltdc_irq(int irq, void *arg) · 22 unmodified lines | ||
| 390 | 690 | struct drm_device *ddev = arg; |
| 391 | 691 | struct ltdc_device *ldev = ddev->dev_private; |
| 392 | 692 | |
| 393 | − /* Read & Clear the interrupt status */ | |
| 394 | − ldev->irq_status = reg_read(ldev->regs, LTDC_ISR); | |
| 395 | − reg_write(ldev->regs, LTDC_ICR, ldev->irq_status); | |
| 693 | + /* | |
| 694 | + * Read & Clear the interrupt status | |
| 695 | + * In order to write / read registers in this critical section | |
| 696 | + * very quickly, the regmap functions are not used. | |
| 697 | + */ | |
| 698 | + ldev->irq_status = readl_relaxed(ldev->regs + LTDC_ISR); | |
| 699 | + writel_relaxed(ldev->irq_status, ldev->regs + LTDC_ICR); | |
| 396 | 700 | |
| 397 | 701 | return IRQ_WAKE_THREAD; |
| 398 | 702 | } |
| @@ -416,7 +720,7 @@ static void ltdc_crtc_update_clut(struct drm_crtc *crtc) · 17 unmodified lines | ||
| 416 | 720 | for (i = 0; i < CLUT_SIZE; i++, lut++) { |
| 417 | 721 | val = ((lut->red << 8) & 0xff0000) | (lut->green & 0xff00) | |
| 418 | 722 | (lut->blue >> 8) | (i << 24); |
| 419 | − reg_write(ldev->regs, LTDC_L1CLUTWR, val); | |
| 723 | + regmap_write(ldev->regmap, LTDC_L1CLUTWR, val); | |
| 420 | 724 | } |
| 421 | 725 | } |
| 422 | 726 | |
| @@ -431,13 +735,14 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, · 8 unmodified lines | ||
| 431 | 735 | pm_runtime_get_sync(ddev->dev); |
| 432 | 736 | |
| 433 | 737 | /* Sets the background color value */ |
| 434 | − reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); | |
| 738 | + regmap_write(ldev->regmap, LTDC_BCCR, BCCR_BCBLACK); | |
| 435 | 739 | |
| 436 | 740 | /* Enable IRQ */ |
| 437 | − reg_set(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); | |
| 741 | + regmap_set_bits(ldev->regmap, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); | |
| 438 | 742 | |
| 439 | 743 | /* Commit shadow registers = update planes at next vblank */ |
| 440 | − reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); | |
| 744 | + if (!ldev->caps.plane_reg_shadow) | |
| 745 | + regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_VBR); | |
| 441 | 746 | |
| 442 | 747 | drm_crtc_vblank_on(crtc); |
| 443 | 748 | } |
| @@ -453,10 +758,11 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, · 9 unmodified lines | ||
| 453 | 758 | drm_crtc_vblank_off(crtc); |
| 454 | 759 | |
| 455 | 760 | /* disable IRQ */ |
| 456 | − reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); | |
| 761 | + regmap_clear_bits(ldev->regmap, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); | |
| 457 | 762 | |
| 458 | 763 | /* immediately commit disable of layers before switching off LTDC */ |
| 459 | − reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); | |
| 764 | + if (!ldev->caps.plane_reg_shadow) | |
| 765 | + regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_IMR); | |
| 460 | 766 | |
| 461 | 767 | pm_runtime_put_sync(ddev->dev); |
| 462 | 768 | } |
| @@ -533,6 +839,7 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) · 70 unmodified lines | ||
| 533 | 839 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; |
| 534 | 840 | u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; |
| 535 | 841 | u32 total_width, total_height; |
| 842 | + u32 bus_formats = MEDIA_BUS_FMT_RGB888_1X24; | |
| 536 | 843 | u32 bus_flags = 0; |
| 537 | 844 | u32 val; |
| 538 | 845 | int ret; |
| @@ -558,8 +865,11 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) · 19 unmodified lines | ||
| 558 | 865 | |
| 559 | 866 | if (bridge && bridge->timings) |
| 560 | 867 | bus_flags = bridge->timings->input_bus_flags; |
| 561 | − else if (connector) | |
| 868 | + else if (connector) { | |
| 562 | 869 | bus_flags = connector->display_info.bus_flags; |
| 870 | + if (connector->display_info.num_bus_formats) | |
| 871 | + bus_formats = connector->display_info.bus_formats[0]; | |
| 872 | + } | |
| 563 | 873 | |
| 564 | 874 | if (!pm_runtime_active(ddev->dev)) { |
| 565 | 875 | ret = pm_runtime_get_sync(ddev->dev); |
| @@ -604,26 +914,56 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) · 38 unmodified lines | ||
| 604 | 914 | if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) |
| 605 | 915 | val |= GCR_PCPOL; |
| 606 | 916 | |
| 607 | − reg_update_bits(ldev->regs, LTDC_GCR, | |
| 608 | − GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val); | |
| 917 | + regmap_update_bits(ldev->regmap, LTDC_GCR, | |
| 918 | + GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val); | |
| 609 | 919 | |
| 610 | 920 | /* Set Synchronization size */ |
| 611 | 921 | val = (hsync << 16) | vsync; |
| 612 | − reg_update_bits(ldev->regs, LTDC_SSCR, SSCR_VSH | SSCR_HSW, val); | |
| 922 | + regmap_update_bits(ldev->regmap, LTDC_SSCR, SSCR_VSH | SSCR_HSW, val); | |
| 613 | 923 | |
| 614 | 924 | /* Set Accumulated Back porch */ |
| 615 | 925 | val = (accum_hbp << 16) | accum_vbp; |
| 616 | − reg_update_bits(ldev->regs, LTDC_BPCR, BPCR_AVBP | BPCR_AHBP, val); | |
| 926 | + regmap_update_bits(ldev->regmap, LTDC_BPCR, BPCR_AVBP | BPCR_AHBP, val); | |
| 617 | 927 | |
| 618 | 928 | /* Set Accumulated Active Width */ |
| 619 | 929 | val = (accum_act_w << 16) | accum_act_h; |
| 620 | − reg_update_bits(ldev->regs, LTDC_AWCR, AWCR_AAW | AWCR_AAH, val); | |
| 930 | + regmap_update_bits(ldev->regmap, LTDC_AWCR, AWCR_AAW | AWCR_AAH, val); | |
| 621 | 931 | |
| 622 | 932 | /* Set total width & height */ |
| 623 | 933 | val = (total_width << 16) | total_height; |
| 624 | − reg_update_bits(ldev->regs, LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val); | |
| 934 | + regmap_update_bits(ldev->regmap, LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val); | |
| 625 | 935 | |
| 626 | − reg_write(ldev->regs, LTDC_LIPCR, (accum_act_h + 1)); | |
| 936 | + regmap_write(ldev->regmap, LTDC_LIPCR, (accum_act_h + 1)); | |
| 937 | + | |
| 938 | + /* Configure the output format (hw version dependent) */ | |
| 939 | + if (ldev->caps.ycbcr_output) { | |
| 940 | + /* Input video dynamic_range & colorimetry */ | |
| 941 | + int vic = drm_match_cea_mode(mode); | |
| 942 | + u32 val; | |
| 943 | + | |
| 944 | + if (vic == 6 || vic == 7 || vic == 21 || vic == 22 || | |
| 945 | + vic == 2 || vic == 3 || vic == 17 || vic == 18) | |
| 946 | + /* ITU-R BT.601 */ | |
| 947 | + val = 0; | |
| 948 | + else | |
| 949 | + /* ITU-R BT.709 */ | |
| 950 | + val = EDCR_OCYSEL; | |
| 951 | + | |
| 952 | + switch (bus_formats) { | |
| 953 | + case MEDIA_BUS_FMT_YUYV8_1X16: | |
| 954 | + /* enable ycbcr output converter */ | |
| 955 | + regmap_write(ldev->regmap, LTDC_EDCR, EDCR_OCYEN | val); | |
| 956 | + break; | |
| 957 | + case MEDIA_BUS_FMT_YVYU8_1X16: | |
| 958 | + /* enable ycbcr output converter & invert chrominance order */ | |
| 959 | + regmap_write(ldev->regmap, LTDC_EDCR, EDCR_OCYEN | EDCR_OCYCO | val); | |
| 960 | + break; | |
| 961 | + default: | |
| 962 | + /* disable ycbcr output converter */ | |
| 963 | + regmap_write(ldev->regmap, LTDC_EDCR, 0); | |
| 964 | + break; | |
| 965 | + } | |
| 966 | + } | |
| 627 | 967 | } |
| 628 | 968 | |
| 629 | 969 | static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, |
| @@ -638,7 +978,8 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, · 8 unmodified lines | ||
| 638 | 978 | ltdc_crtc_update_clut(crtc); |
| 639 | 979 | |
| 640 | 980 | /* Commit shadow registers = update planes at next vblank */ |
| 641 | − reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); | |
| 981 | + if (!ldev->caps.plane_reg_shadow) | |
| 982 | + regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_VBR); | |
| 642 | 983 | |
| 643 | 984 | if (event) { |
| 644 | 985 | crtc->state->event = NULL; |
| @@ -680,10 +1021,14 @@ static bool ltdc_crtc_get_scanout_position(struct drm_crtc *crtc, · 35 unmodified lines | ||
| 680 | 1021 | * simplify the code and only test if line > vactive_end |
| 681 | 1022 | */ |
| 682 | 1023 | if (pm_runtime_active(ddev->dev)) { |
| 683 | − line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS; | |
| 684 | − vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP; | |
| 685 | − vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH; | |
| 686 | − vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH; | |
| 1024 | + regmap_read(ldev->regmap, LTDC_CPSR, &line); | |
| 1025 | + line &= CPSR_CYPOS; | |
| 1026 | + regmap_read(ldev->regmap, LTDC_BPCR, &vactive_start); | |
| 1027 | + vactive_start &= BPCR_AVBP; | |
| 1028 | + regmap_read(ldev->regmap, LTDC_AWCR, &vactive_end); | |
| 1029 | + vactive_end &= AWCR_AAH; | |
| 1030 | + regmap_read(ldev->regmap, LTDC_TWCR, &vtotal); | |
| 1031 | + vtotal &= TWCR_TOTALH; | |
| 687 | 1032 | |
| 688 | 1033 | if (line > vactive_end) |
| 689 | 1034 | *vpos = line - vtotal - vactive_start; |
| @@ -719,7 +1064,7 @@ static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc) · 29 unmodified lines | ||
| 719 | 1064 | DRM_DEBUG_DRIVER("\n"); |
| 720 | 1065 | |
| 721 | 1066 | if (state->enable) |
| 722 | − reg_set(ldev->regs, LTDC_IER, IER_LIE); | |
| 1067 | + regmap_set_bits(ldev->regmap, LTDC_IER, IER_LIE); | |
| 723 | 1068 | else |
| 724 | 1069 | return -EPERM; |
| 725 | 1070 | |
| @@ -731,7 +1076,7 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc) · 5 unmodified lines | ||
| 731 | 1076 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); |
| 732 | 1077 | |
| 733 | 1078 | DRM_DEBUG_DRIVER("\n"); |
| 734 | − reg_clear(ldev->regs, LTDC_IER, IER_LIE); | |
| 1079 | + regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE); | |
| 735 | 1080 | } |
| 736 | 1081 | |
| 737 | 1082 | static const struct drm_crtc_funcs ltdc_crtc_funcs = { |
| @@ -789,7 +1134,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, · 51 unmodified lines | ||
| 789 | 1134 | u32 y0 = newstate->crtc_y; |
| 790 | 1135 | u32 y1 = newstate->crtc_y + newstate->crtc_h - 1; |
| 791 | 1136 | u32 src_x, src_y, src_w, src_h; |
| 792 | − u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr; | |
| 1137 | + u32 val, pitch_in_bytes, line_length, line_number, paddr, ahbp, avbp, bpcr; | |
| 793 | 1138 | enum ltdc_pix_fmt pf; |
| 794 | 1139 | |
| 795 | 1140 | if (!newstate->crtc || !fb) { |
| @@ -809,19 +1154,20 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, · 13 unmodified lines | ||
| 809 | 1154 | newstate->crtc_w, newstate->crtc_h, |
| 810 | 1155 | newstate->crtc_x, newstate->crtc_y); |
| 811 | 1156 | |
| 812 | − bpcr = reg_read(ldev->regs, LTDC_BPCR); | |
| 1157 | + regmap_read(ldev->regmap, LTDC_BPCR, &bpcr); | |
| 1158 | + | |
| 813 | 1159 | ahbp = (bpcr & BPCR_AHBP) >> 16; |
| 814 | 1160 | avbp = bpcr & BPCR_AVBP; |
| 815 | 1161 | |
| 816 | 1162 | /* Configures the horizontal start and stop position */ |
| 817 | 1163 | val = ((x1 + 1 + ahbp) << 16) + (x0 + 1 + ahbp); |
| 818 | − reg_update_bits(ldev->regs, LTDC_L1WHPCR + lofs, | |
| 819 | − LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); | |
| 1164 | + regmap_write_bits(ldev->regmap, LTDC_L1WHPCR + lofs, | |
| 1165 | + LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); | |
| 820 | 1166 | |
| 821 | 1167 | /* Configures the vertical start and stop position */ |
| 822 | 1168 | val = ((y1 + 1 + avbp) << 16) + (y0 + 1 + avbp); |
| 823 | − reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, | |
| 824 | − LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); | |
| 1169 | + regmap_write_bits(ldev->regmap, LTDC_L1WVPCR + lofs, | |
| 1170 | + LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); | |
| 825 | 1171 | |
| 826 | 1172 | /* Specifies the pixel format */ |
| 827 | 1173 | pf = to_ltdc_pixelformat(fb->format->format); |
| @@ -829,24 +1175,27 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, · 1 unmodified line | ||
| 829 | 1175 | if (ldev->caps.pix_fmt_hw[val] == pf) |
| 830 | 1176 | break; |
| 831 | 1177 | |
| 1178 | + /* Use the flexible color format feature if necessary and available */ | |
| 1179 | + if (ldev->caps.pix_fmt_flex && val == NB_PF) | |
| 1180 | + val = ltdc_set_flexible_pixel_format(plane, pf); | |
| 1181 | + | |
| 832 | 1182 | if (val == NB_PF) { |
| 833 | 1183 | DRM_ERROR("Pixel format %.4s not supported\n", |
| 834 | 1184 | (char *)&fb->format->format); |
| 835 | 1185 | val = 0; /* set by default ARGB 32 bits */ |
| 836 | 1186 | } |
| 837 | − reg_update_bits(ldev->regs, LTDC_L1PFCR + lofs, LXPFCR_PF, val); | |
| 1187 | + regmap_write_bits(ldev->regmap, LTDC_L1PFCR + lofs, LXPFCR_PF, val); | |
| 838 | 1188 | |
| 839 | 1189 | /* Configures the color frame buffer pitch in bytes & line length */ |
| 840 | 1190 | pitch_in_bytes = fb->pitches[0]; |
| 841 | 1191 | line_length = fb->format->cpp[0] * |
| 842 | 1192 | (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; |
| 843 | 1193 | val = ((pitch_in_bytes << 16) | line_length); |
| 844 | − reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, | |
| 845 | − LXCFBLR_CFBLL | LXCFBLR_CFBP, val); | |
| 1194 | + regmap_write_bits(ldev->regmap, LTDC_L1CFBLR + lofs, LXCFBLR_CFBLL | LXCFBLR_CFBP, val); | |
| 846 | 1195 | |
| 847 | 1196 | /* Specifies the constant alpha value */ |
| 848 | 1197 | val = newstate->alpha >> 8; |
| 849 | − reg_update_bits(ldev->regs, LTDC_L1CACR + lofs, LXCACR_CONSTA, val); | |
| 1198 | + regmap_write_bits(ldev->regmap, LTDC_L1CACR + lofs, LXCACR_CONSTA, val); | |
| 850 | 1199 | |
| 851 | 1200 | /* Specifies the blending factors */ |
| 852 | 1201 | val = BF1_PAXCA | BF2_1PAXCA; |
| @@ -858,24 +1207,98 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, · 5 unmodified lines | ||
| 858 | 1207 | plane->type != DRM_PLANE_TYPE_PRIMARY) |
| 859 | 1208 | val = BF1_PAXCA | BF2_1PAXCA; |
| 860 | 1209 | |
| 861 | − reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs, | |
| 862 | − LXBFCR_BF2 | LXBFCR_BF1, val); | |
| 1210 | + regmap_write_bits(ldev->regmap, LTDC_L1BFCR + lofs, LXBFCR_BF2 | LXBFCR_BF1, val); | |
| 863 | 1211 | |
| 864 | 1212 | /* Configures the frame buffer line number */ |
| 865 | − val = y1 - y0 + 1; | |
| 866 | − reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); | |
| 1213 | + line_number = y1 - y0 + 1; | |
| 1214 | + regmap_write_bits(ldev->regmap, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, line_number); | |
| 867 | 1215 | |
| 868 | 1216 | /* Sets the FB address */ |
| 869 | 1217 | paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 0); |
| 870 | 1218 | |
| 871 | 1219 | DRM_DEBUG_DRIVER("fb: phys 0x%08x", paddr); |
| 872 | − reg_write(ldev->regs, LTDC_L1CFBAR + lofs, paddr); | |
| 1220 | + regmap_write(ldev->regmap, LTDC_L1CFBAR + lofs, paddr); | |
| 1221 | + | |
| 1222 | + if (ldev->caps.ycbcr_input) { | |
| 1223 | + if (fb->format->is_yuv) { | |
| 1224 | + switch (fb->format->format) { | |
| 1225 | + case DRM_FORMAT_NV12: | |
| 1226 | + case DRM_FORMAT_NV21: | |
| 1227 | + /* Configure the auxiliary frame buffer address 0 & 1 */ | |
| 1228 | + paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); | |
| 1229 | + regmap_write(ldev->regmap, LTDC_L1AFBA0R + lofs, paddr); | |
| 1230 | + regmap_write(ldev->regmap, LTDC_L1AFBA1R + lofs, paddr + 1); | |
| 1231 | + | |
| 1232 | + /* Configure the buffer length */ | |
| 1233 | + val = ((pitch_in_bytes << 16) | line_length); | |
| 1234 | + regmap_write(ldev->regmap, LTDC_L1AFBLR + lofs, val); | |
| 1235 | + | |
| 1236 | + /* Configure the frame buffer line number */ | |
| 1237 | + val = (line_number >> 1); | |
| 1238 | + regmap_write(ldev->regmap, LTDC_L1AFBLNR + lofs, val); | |
| 1239 | + break; | |
| 1240 | + case DRM_FORMAT_YUV420: | |
| 1241 | + /* Configure the auxiliary frame buffer address 0 */ | |
| 1242 | + paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); | |
| 1243 | + regmap_write(ldev->regmap, LTDC_L1AFBA0R + lofs, paddr); | |
| 1244 | + | |
| 1245 | + /* Configure the auxiliary frame buffer address 1 */ | |
| 1246 | + paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 2); | |
| 1247 | + regmap_write(ldev->regmap, LTDC_L1AFBA1R + lofs, paddr); | |
| 1248 | + | |
| 1249 | + line_length = ((fb->format->cpp[0] * (x1 - x0 + 1)) >> 1) + | |
| 1250 | + (ldev->caps.bus_width >> 3) - 1; | |
| 1251 | + | |
| 1252 | + /* Configure the buffer length */ | |
| 1253 | + val = (((pitch_in_bytes >> 1) << 16) | line_length); | |
| 1254 | + regmap_write(ldev->regmap, LTDC_L1AFBLR + lofs, val); | |
| 1255 | + | |
| 1256 | + /* Configure the frame buffer line number */ | |
| 1257 | + val = (line_number >> 1); | |
| 1258 | + regmap_write(ldev->regmap, LTDC_L1AFBLNR + lofs, val); | |
| 1259 | + break; | |
| 1260 | + case DRM_FORMAT_YVU420: | |
| 1261 | + /* Configure the auxiliary frame buffer address 0 */ | |
| 1262 | + paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 2); | |
| 1263 | + regmap_write(ldev->regmap, LTDC_L1AFBA0R + lofs, paddr); | |
| 1264 | + | |
| 1265 | + /* Configure the auxiliary frame buffer address 1 */ | |
| 1266 | + paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); | |
| 1267 | + regmap_write(ldev->regmap, LTDC_L1AFBA1R + lofs, paddr); | |
| 1268 | + | |
| 1269 | + line_length = ((fb->format->cpp[0] * (x1 - x0 + 1)) >> 1) + | |
| 1270 | + (ldev->caps.bus_width >> 3) - 1; | |
| 1271 | + | |
| 1272 | + /* Configure the buffer length */ | |
| 1273 | + val = (((pitch_in_bytes >> 1) << 16) | line_length); | |
| 1274 | + regmap_write(ldev->regmap, LTDC_L1AFBLR + lofs, val); | |
| 1275 | + | |
| 1276 | + /* Configure the frame buffer line number */ | |
| 1277 | + val = (line_number >> 1); | |
| 1278 | + regmap_write(ldev->regmap, LTDC_L1AFBLNR + lofs, val); | |
| 1279 | + break; | |
| 1280 | + } | |
| 1281 | + | |
| 1282 | + /* Configure YCbC conversion coefficient */ | |
| 1283 | + ltdc_set_ycbcr_coeffs(plane); | |
| 1284 | + | |
| 1285 | + /* Configure YCbCr format and enable/disable conversion */ | |
| 1286 | + ltdc_set_ycbcr_config(plane, fb->format->format); | |
| 1287 | + } else { | |
| 1288 | + /* disable ycbcr conversion */ | |
| 1289 | + regmap_write(ldev->regmap, LTDC_L1PCR + lofs, 0); | |
| 1290 | + } | |
| 1291 | + } | |
| 873 | 1292 | |
| 874 | 1293 | /* Enable layer and CLUT if needed */ |
| 875 | 1294 | val = fb->format->format == DRM_FORMAT_C8 ? LXCR_CLUTEN : 0; |
| 876 | 1295 | val |= LXCR_LEN; |
| 877 | − reg_update_bits(ldev->regs, LTDC_L1CR + lofs, | |
| 878 | − LXCR_LEN | LXCR_CLUTEN, val); | |
| 1296 | + regmap_write_bits(ldev->regmap, LTDC_L1CR + lofs, LXCR_LEN | LXCR_CLUTEN, val); | |
| 1297 | + | |
| 1298 | + /* Commit shadow registers = update plane at next vblank */ | |
| 1299 | + if (ldev->caps.plane_reg_shadow) | |
| 1300 | + regmap_write_bits(ldev->regmap, LTDC_L1RCR + lofs, | |
| 1301 | + LXRCR_IMR | LXRCR_VBR | LXRCR_GRMSK, LXRCR_VBR); | |
| 879 | 1302 | |
| 880 | 1303 | ldev->plane_fpsi[plane->index].counter++; |
| 881 | 1304 | |
| @@ -900,7 +1323,12 @@ static void ltdc_plane_atomic_disable(struct drm_plane *plane, · 18 unmodified lines | ||
| 900 | 1323 | u32 lofs = plane->index * LAY_OFS; |
| 901 | 1324 | |
| 902 | 1325 | /* disable layer */ |
| 903 | − reg_clear(ldev->regs, LTDC_L1CR + lofs, LXCR_LEN); | |
| 1326 | + regmap_write_bits(ldev->regmap, LTDC_L1CR + lofs, LXCR_LEN, 0); | |
| 1327 | + | |
| 1328 | + /* Commit shadow registers = update plane at next vblank */ | |
| 1329 | + if (ldev->caps.plane_reg_shadow) | |
| 1330 | + regmap_write_bits(ldev->regmap, LTDC_L1RCR + lofs, | |
| 1331 | + LXRCR_IMR | LXRCR_VBR | LXRCR_GRMSK, LXRCR_VBR); | |
| 904 | 1332 | |
| 905 | 1333 | DRM_DEBUG_DRIVER("CRTC:%d plane:%d\n", |
| 906 | 1334 | oldstate->crtc->base.id, plane->base.id); |
| @@ -925,16 +1353,6 @@ static void ltdc_plane_atomic_print_state(struct drm_printer *p, · 18 unmodified lines | ||
| 925 | 1353 | fpsi->counter = 0; |
| 926 | 1354 | } |
| 927 | 1355 | |
| 928 | −static bool ltdc_plane_format_mod_supported(struct drm_plane *plane, | |
| 929 | − u32 format, | |
| 930 | − u64 modifier) | |
| 931 | −{ | |
| 932 | − if (modifier == DRM_FORMAT_MOD_LINEAR) | |
| 933 | − return true; | |
| 934 | − | |
| 935 | − return false; | |
| 936 | −} | |
| 937 | − | |
| 938 | 1356 | static const struct drm_plane_funcs ltdc_plane_funcs = { |
| 939 | 1357 | .update_plane = drm_atomic_helper_update_plane, |
| 940 | 1358 | .disable_plane = drm_atomic_helper_disable_plane, |
| @@ -943,7 +1361,6 @@ static const struct drm_plane_funcs ltdc_plane_funcs = { · 2 unmodified lines | ||
| 943 | 1361 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, |
| 944 | 1362 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, |
| 945 | 1363 | .atomic_print_state = ltdc_plane_atomic_print_state, |
| 946 | − .format_mod_supported = ltdc_plane_format_mod_supported, | |
| 947 | 1364 | }; |
| 948 | 1365 | |
| 949 | 1366 | static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { |
| @@ -953,36 +1370,58 @@ static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { · 3 unmodified lines | ||
| 953 | 1370 | }; |
| 954 | 1371 | |
| 955 | 1372 | static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, |
| 956 | − enum drm_plane_type type) | |
| 1373 | + enum drm_plane_type type, | |
| 1374 | + int index) | |
| 957 | 1375 | { |
| 958 | 1376 | unsigned long possible_crtcs = CRTC_MASK; |
| 959 | 1377 | struct ltdc_device *ldev = ddev->dev_private; |
| 960 | 1378 | struct device *dev = ddev->dev; |
| 961 | 1379 | struct drm_plane *plane; |
| 962 | 1380 | unsigned int i, nb_fmt = 0; |
| 963 | − u32 formats[NB_PF * 2]; | |
| 964 | − u32 drm_fmt, drm_fmt_no_alpha; | |
| 1381 | + u32 *formats; | |
| 1382 | + u32 drm_fmt; | |
| 965 | 1383 | const u64 *modifiers = ltdc_format_modifiers; |
| 1384 | + u32 lofs = index * LAY_OFS; | |
| 1385 | + u32 val; | |
| 966 | 1386 | int ret; |
| 967 | 1387 | |
| 968 | − /* Get supported pixel formats */ | |
| 969 | − for (i = 0; i < NB_PF; i++) { | |
| 970 | − drm_fmt = to_drm_pixelformat(ldev->caps.pix_fmt_hw[i]); | |
| 971 | − if (!drm_fmt) | |
| 972 | − continue; | |
| 973 | − formats[nb_fmt++] = drm_fmt; | |
| 1388 | + /* Allocate the biggest size according to supported color formats */ | |
| 1389 | + formats = devm_kzalloc(dev, (ldev->caps.pix_fmt_nb + | |
| 1390 | + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_cp) + | |
| 1391 | + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_sp) + | |
| 1392 | + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_fp)) * | |
| 1393 | + sizeof(*formats), GFP_KERNEL); | |
| 974 | 1394 | |
| 975 | − /* Add the no-alpha related format if any & supported */ | |
| 976 | − drm_fmt_no_alpha = get_pixelformat_without_alpha(drm_fmt); | |
| 977 | − if (!drm_fmt_no_alpha) | |
| 978 | − continue; | |
| 1395 | + for (i = 0; i < ldev->caps.pix_fmt_nb; i++) { | |
| 1396 | + drm_fmt = ldev->caps.pix_fmt_drm[i]; | |
| 979 | 1397 | |
| 980 | 1398 | /* Manage hw-specific capabilities */ |
| 981 | − if (ldev->caps.non_alpha_only_l1 && | |
| 982 | − type != DRM_PLANE_TYPE_PRIMARY) | |
| 983 | − continue; | |
| 1399 | + if (ldev->caps.non_alpha_only_l1) | |
| 1400 | + /* XR24 & RX24 like formats supported only on primary layer */ | |
| 1401 | + if (type != DRM_PLANE_TYPE_PRIMARY && is_xrgb(drm_fmt)) | |
| 1402 | + continue; | |
| 984 | 1403 | |
| 985 | − formats[nb_fmt++] = drm_fmt_no_alpha; | |
| 1404 | + formats[nb_fmt++] = drm_fmt; | |
| 1405 | + } | |
| 1406 | + | |
| 1407 | + /* Add YCbCr supported pixel formats */ | |
| 1408 | + if (ldev->caps.ycbcr_input) { | |
| 1409 | + regmap_read(ldev->regmap, LTDC_L1C1R + lofs, &val); | |
| 1410 | + if (val & LXCR_C1R_YIA) { | |
| 1411 | + memcpy(&formats[nb_fmt], ltdc_drm_fmt_ycbcr_cp, | |
| 1412 | + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_cp) * sizeof(*formats)); | |
| 1413 | + nb_fmt += ARRAY_SIZE(ltdc_drm_fmt_ycbcr_cp); | |
| 1414 | + } | |
| 1415 | + if (val & LXCR_C1R_YSPA) { | |
| 1416 | + memcpy(&formats[nb_fmt], ltdc_drm_fmt_ycbcr_sp, | |
| 1417 | + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_sp) * sizeof(*formats)); | |
| 1418 | + nb_fmt += ARRAY_SIZE(ltdc_drm_fmt_ycbcr_sp); | |
| 1419 | + } | |
| 1420 | + if (val & LXCR_C1R_YFPA) { | |
| 1421 | + memcpy(&formats[nb_fmt], ltdc_drm_fmt_ycbcr_fp, | |
| 1422 | + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_fp) * sizeof(*formats)); | |
| 1423 | + nb_fmt += ARRAY_SIZE(ltdc_drm_fmt_ycbcr_fp); | |
| 1424 | + } | |
| 986 | 1425 | } |
| 987 | 1426 | |
| 988 | 1427 | plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); |
| @@ -995,6 +1434,17 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, · 6 unmodified lines | ||
| 995 | 1434 | if (ret < 0) |
| 996 | 1435 | return NULL; |
| 997 | 1436 | |
| 1437 | + if (ldev->caps.ycbcr_input) { | |
| 1438 | + if (val & (LXCR_C1R_YIA | LXCR_C1R_YSPA | LXCR_C1R_YFPA)) | |
| 1439 | + drm_plane_create_color_properties(plane, | |
| 1440 | + BIT(DRM_COLOR_YCBCR_BT601) | | |
| 1441 | + BIT(DRM_COLOR_YCBCR_BT709), | |
| 1442 | + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | | |
| 1443 | + BIT(DRM_COLOR_YCBCR_FULL_RANGE), | |
| 1444 | + DRM_COLOR_YCBCR_BT601, | |
| 1445 | + DRM_COLOR_YCBCR_LIMITED_RANGE); | |
| 1446 | + } | |
| 1447 | + | |
| 998 | 1448 | drm_plane_helper_add(plane, <dc_plane_helper_funcs); |
| 999 | 1449 | |
| 1000 | 1450 | drm_plane_create_alpha_property(plane); |
| @@ -1020,7 +1470,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) · 19 unmodified lines | ||
| 1020 | 1470 | unsigned int i; |
| 1021 | 1471 | int ret; |
| 1022 | 1472 | |
| 1023 | − primary = ltdc_plane_create(ddev, DRM_PLANE_TYPE_PRIMARY); | |
| 1473 | + primary = ltdc_plane_create(ddev, DRM_PLANE_TYPE_PRIMARY, 0); | |
| 1024 | 1474 | if (!primary) { |
| 1025 | 1475 | DRM_ERROR("Can not create primary plane\n"); |
| 1026 | 1476 | return -EINVAL; |
| @@ -1044,7 +1494,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) · 17 unmodified lines | ||
| 1044 | 1494 | |
| 1045 | 1495 | /* Add planes. Note : the first layer is used by primary plane */ |
| 1046 | 1496 | for (i = 1; i < ldev->caps.nb_layers; i++) { |
| 1047 | − overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY); | |
| 1497 | + overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY, i); | |
| 1048 | 1498 | if (!overlay) { |
| 1049 | 1499 | ret = -ENOMEM; |
| 1050 | 1500 | DRM_ERROR("Can not create overlay plane %d\n", i); |
| @@ -1068,7 +1518,7 @@ static void ltdc_encoder_disable(struct drm_encoder *encoder) · 17 unmodified lines | ||
| 1068 | 1518 | DRM_DEBUG_DRIVER("\n"); |
| 1069 | 1519 | |
| 1070 | 1520 | /* Disable LTDC */ |
| 1071 | − reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); | |
| 1521 | + regmap_clear_bits(ldev->regmap, LTDC_GCR, GCR_LTDCEN); | |
| 1072 | 1522 | |
| 1073 | 1523 | /* Set to sleep state the pinctrl whatever type of encoder */ |
| 1074 | 1524 | pinctrl_pm_select_sleep_state(ddev->dev); |
| @@ -1082,7 +1532,7 @@ static void ltdc_encoder_enable(struct drm_encoder *encoder) · 7 unmodified lines | ||
| 1082 | 1532 | DRM_DEBUG_DRIVER("\n"); |
| 1083 | 1533 | |
| 1084 | 1534 | /* Enable LTDC */ |
| 1085 | − reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); | |
| 1535 | + regmap_set_bits(ldev->regmap, LTDC_GCR, GCR_LTDCEN); | |
| 1086 | 1536 | } |
| 1087 | 1537 | |
| 1088 | 1538 | static void ltdc_encoder_mode_set(struct drm_encoder *encoder, |
| @@ -1145,21 +1595,25 @@ static int ltdc_get_caps(struct drm_device *ddev) · 56 unmodified lines | ||
| 1145 | 1595 | * at least 1 layer must be managed & the number of layers |
| 1146 | 1596 | * must not exceed LTDC_MAX_LAYER |
| 1147 | 1597 | */ |
| 1148 | − lcr = reg_read(ldev->regs, LTDC_LCR); | |
| 1598 | + regmap_read(ldev->regmap, LTDC_LCR, &lcr); | |
| 1149 | 1599 | |
| 1150 | 1600 | ldev->caps.nb_layers = clamp((int)lcr, 1, LTDC_MAX_LAYER); |
| 1151 | 1601 | |
| 1152 | 1602 | /* set data bus width */ |
| 1153 | − gc2r = reg_read(ldev->regs, LTDC_GC2R); | |
| 1603 | + regmap_read(ldev->regmap, LTDC_GC2R, &gc2r); | |
| 1154 | 1604 | bus_width_log2 = (gc2r & GC2R_BW) >> 4; |
| 1155 | 1605 | ldev->caps.bus_width = 8 << bus_width_log2; |
| 1156 | − ldev->caps.hw_version = reg_read(ldev->regs, LTDC_IDR); | |
| 1606 | + regmap_read(ldev->regmap, LTDC_IDR, &ldev->caps.hw_version); | |
| 1157 | 1607 | |
| 1158 | 1608 | switch (ldev->caps.hw_version) { |
| 1159 | 1609 | case HWVER_10200: |
| 1160 | 1610 | case HWVER_10300: |
| 1161 | − ldev->caps.reg_ofs = REG_OFS_NONE; | |
| 1611 | + ldev->caps.layer_ofs = LAY_OFS_0; | |
| 1612 | + ldev->caps.layer_regs = ltdc_layer_regs_a0; | |
| 1162 | 1613 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a0; |
| 1614 | + ldev->caps.pix_fmt_drm = ltdc_drm_fmt_a0; | |
| 1615 | + ldev->caps.pix_fmt_nb = ARRAY_SIZE(ltdc_drm_fmt_a0); | |
| 1616 | + ldev->caps.pix_fmt_flex = false; | |
| 1163 | 1617 | /* |
| 1164 | 1618 | * Hw older versions support non-alpha color formats derived |
| 1165 | 1619 | * from native alpha color formats only on the primary layer. |
| @@ -1172,13 +1626,37 @@ static int ltdc_get_caps(struct drm_device *ddev) · 6 unmodified lines | ||
| 1172 | 1626 | if (ldev->caps.hw_version == HWVER_10200) |
| 1173 | 1627 | ldev->caps.pad_max_freq_hz = 65000000; |
| 1174 | 1628 | ldev->caps.nb_irq = 2; |
| 1629 | + ldev->caps.ycbcr_input = false; | |
| 1630 | + ldev->caps.ycbcr_output = false; | |
| 1631 | + ldev->caps.plane_reg_shadow = false; | |
| 1175 | 1632 | break; |
| 1176 | 1633 | case HWVER_20101: |
| 1177 | − ldev->caps.reg_ofs = REG_OFS_4; | |
| 1634 | + ldev->caps.layer_ofs = LAY_OFS_0; | |
| 1635 | + ldev->caps.layer_regs = ltdc_layer_regs_a1; | |
| 1178 | 1636 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1; |
| 1637 | + ldev->caps.pix_fmt_drm = ltdc_drm_fmt_a1; | |
| 1638 | + ldev->caps.pix_fmt_nb = ARRAY_SIZE(ltdc_drm_fmt_a1); | |
| 1639 | + ldev->caps.pix_fmt_flex = false; | |
| 1179 | 1640 | ldev->caps.non_alpha_only_l1 = false; |
| 1180 | 1641 | ldev->caps.pad_max_freq_hz = 150000000; |
| 1181 | 1642 | ldev->caps.nb_irq = 4; |
| 1643 | + ldev->caps.ycbcr_input = false; | |
| 1644 | + ldev->caps.ycbcr_output = false; | |
| 1645 | + ldev->caps.plane_reg_shadow = false; | |
| 1646 | + break; | |
| 1647 | + case HWVER_40100: | |
| 1648 | + ldev->caps.layer_ofs = LAY_OFS_1; | |
| 1649 | + ldev->caps.layer_regs = ltdc_layer_regs_a2; | |
| 1650 | + ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a2; | |
| 1651 | + ldev->caps.pix_fmt_drm = ltdc_drm_fmt_a2; | |
| 1652 | + ldev->caps.pix_fmt_nb = ARRAY_SIZE(ltdc_drm_fmt_a2); | |
| 1653 | + ldev->caps.pix_fmt_flex = true; | |
| 1654 | + ldev->caps.non_alpha_only_l1 = false; | |
| 1655 | + ldev->caps.pad_max_freq_hz = 90000000; | |
| 1656 | + ldev->caps.nb_irq = 2; | |
| 1657 | + ldev->caps.ycbcr_input = true; | |
| 1658 | + ldev->caps.ycbcr_output = true; | |
| 1659 | + ldev->caps.plane_reg_shadow = true; | |
| 1182 | 1660 | break; |
| 1183 | 1661 | default: |
| 1184 | 1662 | return -ENODEV; |
| @@ -1296,9 +1774,15 @@ int ltdc_load(struct drm_device *ddev) · 111 unmodified lines | ||
| 1296 | 1774 | goto err; |
| 1297 | 1775 | } |
| 1298 | 1776 | |
| 1777 | + ldev->regmap = devm_regmap_init_mmio(&pdev->dev, ldev->regs, &stm32_ltdc_regmap_cfg); | |
| 1778 | + if (IS_ERR(ldev->regmap)) { | |
| 1779 | + DRM_ERROR("Unable to regmap ltdc registers\n"); | |
| 1780 | + ret = PTR_ERR(ldev->regmap); | |
| 1781 | + goto err; | |
| 1782 | + } | |
| 1783 | + | |
| 1299 | 1784 | /* Disable interrupts */ |
| 1300 | − reg_clear(ldev->regs, LTDC_IER, | |
| 1301 | − IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); | |
| 1785 | + regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); | |
| 1302 | 1786 | |
| 1303 | 1787 | ret = ltdc_get_caps(ddev); |
| 1304 | 1788 | if (ret) { |
| @@ -14,12 +14,19 @@ · 13 unmodified lines | ||
| 14 | 14 | struct ltdc_caps { |
| 15 | 15 | u32 hw_version; /* hardware version */ |
| 16 | 16 | u32 nb_layers; /* number of supported layers */ |
| 17 | − u32 reg_ofs; /* register offset for applicable regs */ | |
| 17 | + u32 layer_ofs; /* layer offset for applicable regs */ | |
| 18 | + const u32 *layer_regs; /* layer register offset */ | |
| 18 | 19 | u32 bus_width; /* bus width (32 or 64 bits) */ |
| 19 | − const u32 *pix_fmt_hw; /* supported pixel formats */ | |
| 20 | + const u32 *pix_fmt_hw; /* supported hw pixel formats */ | |
| 21 | + const u32 *pix_fmt_drm; /* supported drm pixel formats */ | |
| 22 | + int pix_fmt_nb; /* number of pixel format */ | |
| 23 | + bool pix_fmt_flex; /* pixel format flexibility supported */ | |
| 20 | 24 | bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */ |
| 21 | 25 | int pad_max_freq_hz; /* max frequency supported by pad */ |
| 22 | 26 | int nb_irq; /* number of hardware interrupts */ |
| 27 | + bool ycbcr_input; /* ycbcr input converter supported */ | |
| 28 | + bool ycbcr_output; /* ycbcr output converter supported */ | |
| 29 | + bool plane_reg_shadow; /* plane shadow registers ability */ | |
| 23 | 30 | }; |
| 24 | 31 | |
| 25 | 32 | #define LTDC_MAX_LAYER 4 |
| @@ -31,6 +38,7 @@ struct fps_info { · 5 unmodified lines | ||
| 31 | 38 | |
| 32 | 39 | struct ltdc_device { |
| 33 | 40 | void __iomem *regs; |
| 41 | + struct regmap *regmap; | |
| 34 | 42 | struct clk *pixel_clk; /* lcd pixel clock */ |
| 35 | 43 | struct mutex err_lock; /* protecting error_status */ |
| 36 | 44 | struct ltdc_caps caps; |
| @@ -5,6 +5,7 @@ config DRM_TEGRA · 4 unmodified lines | ||
| 5 | 5 | depends on COMMON_CLK |
| 6 | 6 | depends on DRM |
| 7 | 7 | depends on OF |
| 8 | + select DRM_DP_HELPER | |
| 8 | 9 | select DRM_KMS_HELPER |
| 9 | 10 | select DRM_MIPI_DSI |
| 10 | 11 | select DRM_PANEL |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | */ |
| 6 | 6 | |
| 7 | 7 | #include <drm/drm_crtc.h> |
| 8 | −#include <drm/drm_dp_helper.h> | |
| 8 | +#include <drm/dp/drm_dp_helper.h> | |
| 9 | 9 | #include <drm/drm_print.h> |
| 10 | 10 | |
| 11 | 11 | #include "dp.h" |
| @@ -18,7 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/reset.h> |
| 19 | 19 | #include <linux/workqueue.h> |
| 20 | 20 | |
| 21 | −#include <drm/drm_dp_helper.h> | |
| 21 | +#include <drm/dp/drm_dp_helper.h> | |
| 22 | 22 | #include <drm/drm_panel.h> |
| 23 | 23 | |
| 24 | 24 | #include "dp.h" |
| @@ -18,7 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | #include <drm/drm_atomic_helper.h> |
| 20 | 20 | #include <drm/drm_debugfs.h> |
| 21 | −#include <drm/drm_dp_helper.h> | |
| 21 | +#include <drm/dp/drm_dp_helper.h> | |
| 22 | 22 | #include <drm/drm_file.h> |
| 23 | 23 | #include <drm/drm_panel.h> |
| 24 | 24 | #include <drm/drm_scdc_helper.h> |
| @@ -60,8 +60,6 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod) · 59 unmodified lines | ||
| 60 | 60 | list_del(&mod->list); |
| 61 | 61 | } |
| 62 | 62 | |
| 63 | −static struct of_device_id tilcdc_of_match[]; | |
| 64 | − | |
| 65 | 63 | static int tilcdc_atomic_check(struct drm_device *dev, |
| 66 | 64 | struct drm_atomic_state *state) |
| 67 | 65 | { |
| @@ -587,7 +585,7 @@ static int tilcdc_pdev_remove(struct platform_device *pdev) · 519 unmodified lines | ||
| 587 | 585 | return 0; |
| 588 | 586 | } |
| 589 | 587 | |
| 590 | −static struct of_device_id tilcdc_of_match[] = { | |
| 588 | +static const struct of_device_id tilcdc_of_match[] = { | |
| 591 | 589 | { .compatible = "ti,am33xx-tilcdc", }, |
| 592 | 590 | { .compatible = "ti,da850-tilcdc", }, |
| 593 | 591 | { }, |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <drm/drm_gem_framebuffer_helper.h> |
| 11 | 11 | #include <drm/drm_gem_vram_helper.h> |
| 12 | 12 | #include <drm/drm_managed.h> |
| 13 | +#include <drm/drm_module.h> | |
| 13 | 14 | #include <drm/drm_probe_helper.h> |
| 14 | 15 | #include <drm/drm_simple_kms_helper.h> |
| 15 | 16 | |
| @@ -716,24 +717,7 @@ static struct pci_driver bochs_pci_driver = { · 700 unmodified lines | ||
| 716 | 717 | /* ---------------------------------------------------------------------- */ |
| 717 | 718 | /* module init/exit */ |
| 718 | 719 | |
| 719 | −static int __init bochs_init(void) | |
| 720 | −{ | |
| 721 | − if (drm_firmware_drivers_only() && bochs_modeset == -1) | |
| 722 | − return -EINVAL; | |
| 723 | − | |
| 724 | − if (bochs_modeset == 0) | |
| 725 | − return -EINVAL; | |
| 726 | − | |
| 727 | − return pci_register_driver(&bochs_pci_driver); | |
| 728 | −} | |
| 729 | − | |
| 730 | −static void __exit bochs_exit(void) | |
| 731 | −{ | |
| 732 | − pci_unregister_driver(&bochs_pci_driver); | |
| 733 | −} | |
| 734 | − | |
| 735 | −module_init(bochs_init); | |
| 736 | −module_exit(bochs_exit); | |
| 720 | +drm_module_pci_driver_if_modeset(bochs_pci_driver, bochs_modeset); | |
| 737 | 721 | |
| 738 | 722 | MODULE_DEVICE_TABLE(pci, bochs_pci_tbl); |
| 739 | 723 | MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>"); |
| @@ -39,6 +39,7 @@ · 38 unmodified lines | ||
| 39 | 39 | #include <drm/drm_ioctl.h> |
| 40 | 40 | #include <drm/drm_managed.h> |
| 41 | 41 | #include <drm/drm_modeset_helper_vtables.h> |
| 42 | +#include <drm/drm_module.h> | |
| 42 | 43 | #include <drm/drm_probe_helper.h> |
| 43 | 44 | #include <drm/drm_simple_kms_helper.h> |
| 44 | 45 | |
| @@ -633,21 +634,7 @@ static struct pci_driver cirrus_pci_driver = { · 588 unmodified lines | ||
| 633 | 634 | .remove = cirrus_pci_remove, |
| 634 | 635 | }; |
| 635 | 636 | |
| 636 | −static int __init cirrus_init(void) | |
| 637 | −{ | |
| 638 | − if (drm_firmware_drivers_only()) | |
| 639 | − return -EINVAL; | |
| 640 | − | |
| 641 | − return pci_register_driver(&cirrus_pci_driver); | |
| 642 | −} | |
| 643 | − | |
| 644 | −static void __exit cirrus_exit(void) | |
| 645 | −{ | |
| 646 | − pci_unregister_driver(&cirrus_pci_driver); | |
| 647 | −} | |
| 648 | − | |
| 649 | −module_init(cirrus_init); | |
| 650 | −module_exit(cirrus_exit); | |
| 637 | +drm_module_pci_driver(cirrus_pci_driver) | |
| 651 | 638 | |
| 652 | 639 | MODULE_DEVICE_TABLE(pci, pciidlist); |
| 653 | 640 | MODULE_LICENSE("GPL"); |
| @@ -526,21 +526,33 @@ static int simpledrm_device_init_mm(struct simpledrm_device *sdev) · 525 unmodified lines | ||
| 526 | 526 | { |
| 527 | 527 | struct drm_device *dev = &sdev->dev; |
| 528 | 528 | struct platform_device *pdev = sdev->pdev; |
| 529 | − struct resource *mem; | |
| 529 | + struct resource *res, *mem; | |
| 530 | 530 | void __iomem *screen_base; |
| 531 | 531 | int ret; |
| 532 | 532 | |
| 533 | − mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 534 | − if (!mem) | |
| 533 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 534 | + if (!res) | |
| 535 | 535 | return -EINVAL; |
| 536 | 536 | |
| 537 | − ret = devm_aperture_acquire_from_firmware(dev, mem->start, resource_size(mem)); | |
| 537 | + ret = devm_aperture_acquire_from_firmware(dev, res->start, resource_size(res)); | |
| 538 | 538 | if (ret) { |
| 539 | 539 | drm_err(dev, "could not acquire memory range %pr: error %d\n", |
| 540 | − mem, ret); | |
| 540 | + res, ret); | |
| 541 | 541 | return ret; |
| 542 | 542 | } |
| 543 | 543 | |
| 544 | + mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res), | |
| 545 | + sdev->dev.driver->name); | |
| 546 | + if (!mem) { | |
| 547 | + /* | |
| 548 | + * We cannot make this fatal. Sometimes this comes from magic | |
| 549 | + * spaces our resource handlers simply don't know about. Use | |
| 550 | + * the I/O-memory resource as-is and try to map that instead. | |
| 551 | + */ | |
| 552 | + drm_warn(dev, "could not acquire memory region %pr\n", res); | |
| 553 | + mem = res; | |
| 554 | + } | |
| 555 | + | |
| 544 | 556 | screen_base = devm_ioremap_wc(&pdev->dev, mem->start, |
| 545 | 557 | resource_size(mem)); |
| 546 | 558 | if (!screen_base) |
| @@ -241,6 +241,11 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, · 240 unmodified lines | ||
| 241 | 241 | if (bo->type != ttm_bo_type_sg) |
| 242 | 242 | fbo->base.base.resv = &fbo->base.base._resv; |
| 243 | 243 | |
| 244 | + if (fbo->base.resource) { | |
| 245 | + ttm_resource_set_bo(fbo->base.resource, &fbo->base); | |
| 246 | + bo->resource = NULL; | |
| 247 | + } | |
| 248 | + | |
| 244 | 249 | dma_resv_init(&fbo->base.base._resv); |
| 245 | 250 | fbo->base.base.dev = NULL; |
| 246 | 251 | ret = dma_resv_trylock(&fbo->base.base._resv); |
| @@ -509,7 +514,6 @@ static int ttm_bo_move_to_ghost(struct ttm_buffer_object *bo, · 262 unmodified lines | ||
| 509 | 514 | ghost_obj->ttm = NULL; |
| 510 | 515 | else |
| 511 | 516 | bo->ttm = NULL; |
| 512 | − bo->resource = NULL; | |
| 513 | 517 | |
| 514 | 518 | dma_resv_unlock(&ghost_obj->base._resv); |
| 515 | 519 | ttm_bo_put(ghost_obj); |
| @@ -637,7 +641,6 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo) · 121 unmodified lines | ||
| 637 | 641 | dma_resv_unlock(&ghost->base._resv); |
| 638 | 642 | ttm_bo_put(ghost); |
| 639 | 643 | bo->ttm = ttm; |
| 640 | − bo->resource = NULL; | |
| 641 | 644 | ttm_bo_assign_mem(bo, sys_res); |
| 642 | 645 | return 0; |
| 643 | 646 | |
| @@ -89,6 +89,7 @@ static int ttm_range_man_alloc(struct ttm_resource_manager *man, · 88 unmodified lines | ||
| 89 | 89 | spin_unlock(&rman->lock); |
| 90 | 90 | |
| 91 | 91 | if (unlikely(ret)) { |
| 92 | + ttm_resource_fini(man, *res); | |
| 92 | 93 | kfree(node); |
| 93 | 94 | return ret; |
| 94 | 95 | } |
| @@ -108,6 +109,7 @@ static void ttm_range_man_free(struct ttm_resource_manager *man, · 13 unmodified lines | ||
| 108 | 109 | drm_mm_remove_node(&node->mm_nodes[0]); |
| 109 | 110 | spin_unlock(&rman->lock); |
| 110 | 111 | |
| 112 | + ttm_resource_fini(man, res); | |
| 111 | 113 | kfree(node); |
| 112 | 114 | } |
| 113 | 115 | |
| @@ -156,7 +158,7 @@ int ttm_range_man_init_nocheck(struct ttm_device *bdev, · 42 unmodified lines | ||
| 156 | 158 | |
| 157 | 159 | man->func = &ttm_range_manager_func; |
| 158 | 160 | |
| 159 | − ttm_resource_manager_init(man, p_size); | |
| 161 | + ttm_resource_manager_init(man, bdev, p_size); | |
| 160 | 162 | |
| 161 | 163 | drm_mm_init(&rman->mm, 0, p_size); |
| 162 | 164 | spin_lock_init(&rman->lock); |
| @@ -29,6 +29,14 @@ · 28 unmodified lines | ||
| 29 | 29 | #include <drm/ttm/ttm_resource.h> |
| 30 | 30 | #include <drm/ttm/ttm_bo_driver.h> |
| 31 | 31 | |
| 32 | +/** | |
| 33 | + * ttm_resource_init - resource object constructure | |
| 34 | + * @bo: buffer object this resources is allocated for | |
| 35 | + * @place: placement of the resource | |
| 36 | + * @res: the resource object to inistilize | |
| 37 | + * | |
| 38 | + * Initialize a new resource object. Counterpart of &ttm_resource_fini. | |
| 39 | + */ | |
| 32 | 40 | void ttm_resource_init(struct ttm_buffer_object *bo, |
| 33 | 41 | const struct ttm_place *place, |
| 34 | 42 | struct ttm_resource *res) |
| @@ -41,9 +49,25 @@ void ttm_resource_init(struct ttm_buffer_object *bo, · 6 unmodified lines | ||
| 41 | 49 | res->bus.offset = 0; |
| 42 | 50 | res->bus.is_iomem = false; |
| 43 | 51 | res->bus.caching = ttm_cached; |
| 52 | + res->bo = bo; | |
| 44 | 53 | } |
| 45 | 54 | EXPORT_SYMBOL(ttm_resource_init); |
| 46 | 55 | |
| 56 | +/** | |
| 57 | + * ttm_resource_fini - resource destructor | |
| 58 | + * @man: the resource manager this resource belongs to | |
| 59 | + * @res: the resource to clean up | |
| 60 | + * | |
| 61 | + * Should be used by resource manager backends to clean up the TTM resource | |
| 62 | + * objects before freeing the underlying structure. Counterpart of | |
| 63 | + * &ttm_resource_init | |
| 64 | + */ | |
| 65 | +void ttm_resource_fini(struct ttm_resource_manager *man, | |
| 66 | + struct ttm_resource *res) | |
| 67 | +{ | |
| 68 | +} | |
| 69 | +EXPORT_SYMBOL(ttm_resource_fini); | |
| 70 | + | |
| 47 | 71 | int ttm_resource_alloc(struct ttm_buffer_object *bo, |
| 48 | 72 | const struct ttm_place *place, |
| 49 | 73 | struct ttm_resource **res_ptr) |
| @@ -116,20 +140,31 @@ bool ttm_resource_compat(struct ttm_resource *res, · 66 unmodified lines | ||
| 116 | 140 | } |
| 117 | 141 | EXPORT_SYMBOL(ttm_resource_compat); |
| 118 | 142 | |
| 143 | +void ttm_resource_set_bo(struct ttm_resource *res, | |
| 144 | + struct ttm_buffer_object *bo) | |
| 145 | +{ | |
| 146 | + spin_lock(&bo->bdev->lru_lock); | |
| 147 | + res->bo = bo; | |
| 148 | + spin_unlock(&bo->bdev->lru_lock); | |
| 149 | +} | |
| 150 | + | |
| 119 | 151 | /** |
| 120 | 152 | * ttm_resource_manager_init |
| 121 | 153 | * |
| 122 | 154 | * @man: memory manager object to init |
| 155 | + * @bdev: ttm device this manager belongs to | |
| 123 | 156 | * @p_size: size managed area in pages. |
| 124 | 157 | * |
| 125 | 158 | * Initialise core parts of a manager object. |
| 126 | 159 | */ |
| 127 | 160 | void ttm_resource_manager_init(struct ttm_resource_manager *man, |
| 161 | + struct ttm_device *bdev, | |
| 128 | 162 | unsigned long p_size) |
| 129 | 163 | { |
| 130 | 164 | unsigned i; |
| 131 | 165 | |
| 132 | 166 | spin_lock_init(&man->move_lock); |
| 167 | + man->bdev = bdev; | |
| 133 | 168 | man->size = p_size; |
| 134 | 169 | |
| 135 | 170 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) |
| @@ -23,6 +23,7 @@ static int ttm_sys_man_alloc(struct ttm_resource_manager *man, · 22 unmodified lines | ||
| 23 | 23 | static void ttm_sys_man_free(struct ttm_resource_manager *man, |
| 24 | 24 | struct ttm_resource *res) |
| 25 | 25 | { |
| 26 | + ttm_resource_fini(man, res); | |
| 26 | 27 | kfree(res); |
| 27 | 28 | } |
| 28 | 29 | |
| @@ -42,7 +43,7 @@ void ttm_sys_man_init(struct ttm_device *bdev) · 13 unmodified lines | ||
| 42 | 43 | man->use_tt = true; |
| 43 | 44 | man->func = &ttm_sys_manager_func; |
| 44 | 45 | |
| 45 | − ttm_resource_manager_init(man, 0); | |
| 46 | + ttm_resource_manager_init(man, bdev, 0); | |
| 46 | 47 | ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, man); |
| 47 | 48 | ttm_resource_manager_set_used(man, true); |
| 48 | 49 | } |
| @@ -219,6 +219,7 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) · 218 unmodified lines | ||
| 219 | 219 | int ret; |
| 220 | 220 | u32 mmu_debug; |
| 221 | 221 | u32 ident1; |
| 222 | + u64 mask; | |
| 222 | 223 | |
| 223 | 224 | v3d = devm_drm_dev_alloc(dev, &v3d_drm_driver, struct v3d_dev, drm); |
| 224 | 225 | if (IS_ERR(v3d)) |
| @@ -237,8 +238,11 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) · 12 unmodified lines | ||
| 237 | 238 | return ret; |
| 238 | 239 | |
| 239 | 240 | mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); |
| 240 | − dma_set_mask_and_coherent(dev, | |
| 241 | − DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH))); | |
| 241 | + mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); | |
| 242 | + ret = dma_set_mask_and_coherent(dev, mask); | |
| 243 | + if (ret) | |
| 244 | + return ret; | |
| 245 | + | |
| 242 | 246 | v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); |
| 243 | 247 | |
| 244 | 248 | ident1 = V3D_READ(V3D_HUB_IDENT1); |
| @@ -355,8 +355,6 @@ static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev, · 354 unmodified lines | ||
| 355 | 355 | uint32_t page_index = bo_page_index(size); |
| 356 | 356 | struct vc4_bo *bo = NULL; |
| 357 | 357 | |
| 358 | − size = roundup(size, PAGE_SIZE); | |
| 359 | − | |
| 360 | 358 | mutex_lock(&vc4->bo_lock); |
| 361 | 359 | if (page_index >= vc4->bo_cache.size_list_size) |
| 362 | 360 | goto out; |
| @@ -37,6 +37,8 @@ · 36 unmodified lines | ||
| 37 | 37 | #include <drm/drm_fb_helper.h> |
| 38 | 38 | #include <drm/drm_vblank.h> |
| 39 | 39 | |
| 40 | +#include <soc/bcm2835/raspberrypi-firmware.h> | |
| 41 | + | |
| 40 | 42 | #include "uapi/drm/vc4_drm.h" |
| 41 | 43 | |
| 42 | 44 | #include "vc4_drv.h" |
| @@ -215,6 +217,7 @@ static void vc4_match_add_drivers(struct device *dev, · 172 unmodified lines | ||
| 215 | 217 | static int vc4_drm_bind(struct device *dev) |
| 216 | 218 | { |
| 217 | 219 | struct platform_device *pdev = to_platform_device(dev); |
| 220 | + struct rpi_firmware *firmware = NULL; | |
| 218 | 221 | struct drm_device *drm; |
| 219 | 222 | struct vc4_dev *vc4; |
| 220 | 223 | struct device_node *node; |
| @@ -251,15 +254,34 @@ static int vc4_drm_bind(struct device *dev) · 30 unmodified lines | ||
| 251 | 254 | if (ret) |
| 252 | 255 | return ret; |
| 253 | 256 | |
| 254 | − ret = component_bind_all(dev, drm); | |
| 257 | + node = of_find_compatible_node(NULL, NULL, "raspberrypi,bcm2835-firmware"); | |
| 258 | + if (node) { | |
| 259 | + firmware = rpi_firmware_get(node); | |
| 260 | + of_node_put(node); | |
| 261 | + | |
| 262 | + if (!firmware) | |
| 263 | + return -EPROBE_DEFER; | |
| 264 | + } | |
| 265 | + | |
| 266 | + ret = drm_aperture_remove_framebuffers(false, &vc4_drm_driver); | |
| 255 | 267 | if (ret) |
| 256 | 268 | return ret; |
| 257 | 269 | |
| 258 | − ret = vc4_plane_create_additional_planes(drm); | |
| 270 | + if (firmware) { | |
| 271 | + ret = rpi_firmware_property(firmware, | |
| 272 | + RPI_FIRMWARE_NOTIFY_DISPLAY_DONE, | |
| 273 | + NULL, 0); | |
| 274 | + if (ret) | |
| 275 | + drm_warn(drm, "Couldn't stop firmware display driver: %d\n", ret); | |
| 276 | + | |
| 277 | + rpi_firmware_put(firmware); | |
| 278 | + } | |
| 279 | + | |
| 280 | + ret = component_bind_all(dev, drm); | |
| 259 | 281 | if (ret) |
| 260 | − goto unbind_all; | |
| 282 | + return ret; | |
| 261 | 283 | |
| 262 | − ret = drm_aperture_remove_framebuffers(false, &vc4_drm_driver); | |
| 284 | + ret = vc4_plane_create_additional_planes(drm); | |
| 263 | 285 | if (ret) |
| 264 | 286 | goto unbind_all; |
| 265 | 287 | |
| @@ -357,6 +379,9 @@ static int __init vc4_drm_register(void) · 91 unmodified lines | ||
| 357 | 379 | { |
| 358 | 380 | int ret; |
| 359 | 381 | |
| 382 | + if (drm_firmware_drivers_only()) | |
| 383 | + return -ENODEV; | |
| 384 | + | |
| 360 | 385 | ret = platform_register_drivers(component_drivers, |
| 361 | 386 | ARRAY_SIZE(component_drivers)); |
| 362 | 387 | if (ret) |
| @@ -104,6 +104,15 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode) · 103 unmodified lines | ||
| 104 | 104 | return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK; |
| 105 | 105 | } |
| 106 | 106 | |
| 107 | +static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi, | |
| 108 | + const struct drm_display_mode *mode) | |
| 109 | +{ | |
| 110 | + struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder; | |
| 111 | + | |
| 112 | + return !vc4_encoder->hdmi_monitor || | |
| 113 | + drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL; | |
| 114 | +} | |
| 115 | + | |
| 107 | 116 | static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) |
| 108 | 117 | { |
| 109 | 118 | struct drm_info_node *node = (struct drm_info_node *)m->private; |
| @@ -481,7 +490,6 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, · 371 unmodified lines | ||
| 481 | 490 | static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) |
| 482 | 491 | { |
| 483 | 492 | struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); |
| 484 | − struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); | |
| 485 | 493 | struct drm_connector *connector = &vc4_hdmi->connector; |
| 486 | 494 | struct drm_connector_state *cstate = connector->state; |
| 487 | 495 | const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; |
| @@ -499,10 +507,10 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) · 11 unmodified lines | ||
| 499 | 507 | |
| 500 | 508 | drm_hdmi_avi_infoframe_quant_range(&frame.avi, |
| 501 | 509 | connector, mode, |
| 502 | − vc4_encoder->limited_rgb_range ? | |
| 503 | − HDMI_QUANTIZATION_RANGE_LIMITED : | |
| 504 | − HDMI_QUANTIZATION_RANGE_FULL); | |
| 505 | − drm_hdmi_avi_infoframe_colorspace(&frame.avi, cstate); | |
| 510 | + vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode) ? | |
| 511 | + HDMI_QUANTIZATION_RANGE_FULL : | |
| 512 | + HDMI_QUANTIZATION_RANGE_LIMITED); | |
| 513 | + drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate); | |
| 506 | 514 | drm_hdmi_avi_infoframe_bars(&frame.avi, cstate); |
| 507 | 515 | |
| 508 | 516 | vc4_hdmi_write_infoframe(encoder, &frame); |
| @@ -726,7 +734,9 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) · 217 unmodified lines | ||
| 726 | 734 | mutex_unlock(&vc4_hdmi->mutex); |
| 727 | 735 | } |
| 728 | 736 | |
| 729 | −static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) | |
| 737 | +static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, | |
| 738 | + struct drm_connector_state *state, | |
| 739 | + const struct drm_display_mode *mode) | |
| 730 | 740 | { |
| 731 | 741 | unsigned long flags; |
| 732 | 742 | u32 csc_ctl; |
| @@ -736,7 +746,7 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) · 3 unmodified lines | ||
| 736 | 746 | csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, |
| 737 | 747 | VC4_HD_CSC_CTL_ORDER); |
| 738 | 748 | |
| 739 | − if (enable) { | |
| 749 | + if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { | |
| 740 | 750 | /* CEA VICs other than #1 requre limited range RGB |
| 741 | 751 | * output unless overridden by an AVI infoframe. |
| 742 | 752 | * Apply a colorspace conversion to squash 0-255 down |
| @@ -766,44 +776,67 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) · 23 unmodified lines | ||
| 766 | 776 | spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); |
| 767 | 777 | } |
| 768 | 778 | |
| 769 | −static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) | |
| 779 | +/* | |
| 780 | + * If we need to output Full Range RGB, then use the unity matrix | |
| 781 | + * | |
| 782 | + * [ 1 0 0 0] | |
| 783 | + * [ 0 1 0 0] | |
| 784 | + * [ 0 0 1 0] | |
| 785 | + * | |
| 786 | + * Matrix is signed 2p13 fixed point, with signed 9p6 offsets | |
| 787 | + */ | |
| 788 | +static const u16 vc5_hdmi_csc_full_rgb_unity[3][4] = { | |
| 789 | + { 0x2000, 0x0000, 0x0000, 0x0000 }, | |
| 790 | + { 0x0000, 0x2000, 0x0000, 0x0000 }, | |
| 791 | + { 0x0000, 0x0000, 0x2000, 0x0000 }, | |
| 792 | +}; | |
| 793 | + | |
| 794 | +/* | |
| 795 | + * CEA VICs other than #1 require limited range RGB output unless | |
| 796 | + * overridden by an AVI infoframe. Apply a colorspace conversion to | |
| 797 | + * squash 0-255 down to 16-235. The matrix here is: | |
| 798 | + * | |
| 799 | + * [ 0.8594 0 0 16] | |
| 800 | + * [ 0 0.8594 0 16] | |
| 801 | + * [ 0 0 0.8594 16] | |
| 802 | + * | |
| 803 | + * Matrix is signed 2p13 fixed point, with signed 9p6 offsets | |
| 804 | + */ | |
| 805 | +static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = { | |
| 806 | + { 0x1b80, 0x0000, 0x0000, 0x0400 }, | |
| 807 | + { 0x0000, 0x1b80, 0x0000, 0x0400 }, | |
| 808 | + { 0x0000, 0x0000, 0x1b80, 0x0400 }, | |
| 809 | +}; | |
| 810 | + | |
| 811 | +static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi, | |
| 812 | + const u16 coeffs[3][4]) | |
| 770 | 813 | { |
| 771 | − unsigned long flags; | |
| 772 | − u32 csc_ctl; | |
| 814 | + lockdep_assert_held(&vc4_hdmi->hw_lock); | |
| 815 | + | |
| 816 | + HDMI_WRITE(HDMI_CSC_12_11, (coeffs[0][1] << 16) | coeffs[0][0]); | |
| 817 | + HDMI_WRITE(HDMI_CSC_14_13, (coeffs[0][3] << 16) | coeffs[0][2]); | |
| 818 | + HDMI_WRITE(HDMI_CSC_22_21, (coeffs[1][1] << 16) | coeffs[1][0]); | |
| 819 | + HDMI_WRITE(HDMI_CSC_24_23, (coeffs[1][3] << 16) | coeffs[1][2]); | |
| 820 | + HDMI_WRITE(HDMI_CSC_32_31, (coeffs[2][1] << 16) | coeffs[2][0]); | |
| 821 | + HDMI_WRITE(HDMI_CSC_34_33, (coeffs[2][3] << 16) | coeffs[2][2]); | |
| 822 | +} | |
| 773 | 823 | |
| 774 | − csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */ | |
| 824 | +static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, | |
| 825 | + struct drm_connector_state *state, | |
| 826 | + const struct drm_display_mode *mode) | |
| 827 | +{ | |
| 828 | + unsigned long flags; | |
| 829 | + u32 csc_ctl = VC5_MT_CP_CSC_CTL_ENABLE | VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, | |
| 830 | + VC5_MT_CP_CSC_CTL_MODE); | |
| 775 | 831 | |
| 776 | 832 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
| 777 | 833 | |
| 778 | − if (enable) { | |
| 779 | − /* CEA VICs other than #1 requre limited range RGB | |
| 780 | − * output unless overridden by an AVI infoframe. | |
| 781 | − * Apply a colorspace conversion to squash 0-255 down | |
| 782 | − * to 16-235. The matrix here is: | |
| 783 | − * | |
| 784 | − * [ 0.8594 0 0 16] | |
| 785 | − * [ 0 0.8594 0 16] | |
| 786 | − * [ 0 0 0.8594 16] | |
| 787 | − * [ 0 0 0 1] | |
| 788 | − * Matrix is signed 2p13 fixed point, with signed 9p6 offsets | |
| 789 | − */ | |
| 790 | − HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x1b80); | |
| 791 | − HDMI_WRITE(HDMI_CSC_14_13, (0x0400 << 16) | 0x0000); | |
| 792 | − HDMI_WRITE(HDMI_CSC_22_21, (0x1b80 << 16) | 0x0000); | |
| 793 | − HDMI_WRITE(HDMI_CSC_24_23, (0x0400 << 16) | 0x0000); | |
| 794 | − HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); | |
| 795 | − HDMI_WRITE(HDMI_CSC_34_33, (0x0400 << 16) | 0x1b80); | |
| 796 | − } else { | |
| 797 | − /* Still use the matrix for full range, but make it unity. | |
| 798 | − * Matrix is signed 2p13 fixed point, with signed 9p6 offsets | |
| 799 | − */ | |
| 800 | − HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x2000); | |
| 801 | − HDMI_WRITE(HDMI_CSC_14_13, (0x0000 << 16) | 0x0000); | |
| 802 | − HDMI_WRITE(HDMI_CSC_22_21, (0x2000 << 16) | 0x0000); | |
| 803 | − HDMI_WRITE(HDMI_CSC_24_23, (0x0000 << 16) | 0x0000); | |
| 804 | − HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); | |
| 805 | − HDMI_WRITE(HDMI_CSC_34_33, (0x0000 << 16) | 0x2000); | |
| 806 | − } | |
| 834 | + HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); | |
| 835 | + | |
| 836 | + if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) | |
| 837 | + vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb); | |
| 838 | + else | |
| 839 | + vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity); | |
| 807 | 840 | |
| 808 | 841 | HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); |
| 809 | 842 | |
| @@ -889,7 +922,6 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, · 79 unmodified lines | ||
| 889 | 922 | |
| 890 | 923 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
| 891 | 924 | |
| 892 | − HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); | |
| 893 | 925 | HDMI_WRITE(HDMI_HORZA, |
| 894 | 926 | (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) | |
| 895 | 927 | (hsync_pos ? VC5_HDMI_HORZA_HPOS : 0) | |
| @@ -1113,24 +1145,16 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, · 217 unmodified lines | ||
| 1113 | 1145 | struct drm_atomic_state *state) |
| 1114 | 1146 | { |
| 1115 | 1147 | struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); |
| 1148 | + struct drm_connector *connector = &vc4_hdmi->connector; | |
| 1116 | 1149 | struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; |
| 1117 | − struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); | |
| 1150 | + struct drm_connector_state *conn_state = | |
| 1151 | + drm_atomic_get_new_connector_state(state, connector); | |
| 1118 | 1152 | unsigned long flags; |
| 1119 | 1153 | |
| 1120 | 1154 | mutex_lock(&vc4_hdmi->mutex); |
| 1121 | 1155 | |
| 1122 | − if (vc4_encoder->hdmi_monitor && | |
| 1123 | − drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) { | |
| 1124 | − if (vc4_hdmi->variant->csc_setup) | |
| 1125 | − vc4_hdmi->variant->csc_setup(vc4_hdmi, true); | |
| 1126 | − | |
| 1127 | − vc4_encoder->limited_rgb_range = true; | |
| 1128 | − } else { | |
| 1129 | − if (vc4_hdmi->variant->csc_setup) | |
| 1130 | − vc4_hdmi->variant->csc_setup(vc4_hdmi, false); | |
| 1131 | − | |
| 1132 | − vc4_encoder->limited_rgb_range = false; | |
| 1133 | − } | |
| 1156 | + if (vc4_hdmi->variant->csc_setup) | |
| 1157 | + vc4_hdmi->variant->csc_setup(vc4_hdmi, conn_state, mode); | |
| 1134 | 1158 | |
| 1135 | 1159 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
| 1136 | 1160 | HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); |
| @@ -12,7 +12,6 @@ · 11 unmodified lines | ||
| 12 | 12 | struct vc4_hdmi_encoder { |
| 13 | 13 | struct vc4_encoder base; |
| 14 | 14 | bool hdmi_monitor; |
| 15 | − bool limited_rgb_range; | |
| 16 | 15 | }; |
| 17 | 16 | |
| 18 | 17 | static inline struct vc4_hdmi_encoder * |
| @@ -77,7 +76,9 @@ struct vc4_hdmi_variant { · 58 unmodified lines | ||
| 77 | 76 | void (*reset)(struct vc4_hdmi *vc4_hdmi); |
| 78 | 77 | |
| 79 | 78 | /* Callback to enable / disable the CSC */ |
| 80 | − void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, bool enable); | |
| 79 | + void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, | |
| 80 | + struct drm_connector_state *state, | |
| 81 | + const struct drm_display_mode *mode); | |
| 81 | 82 | |
| 82 | 83 | /* Callback to configure the video timings in the HDMI block */ |
| 83 | 84 | void (*set_timings)(struct vc4_hdmi *vc4_hdmi, |
| @@ -774,6 +774,9 @@ enum { · 773 unmodified lines | ||
| 774 | 774 | # define VC4_HD_CSC_CTL_RGB2YCC BIT(1) |
| 775 | 775 | # define VC4_HD_CSC_CTL_ENABLE BIT(0) |
| 776 | 776 | |
| 777 | +# define VC5_MT_CP_CSC_CTL_ENABLE BIT(2) | |
| 778 | +# define VC5_MT_CP_CSC_CTL_MODE_MASK VC4_MASK(1, 0) | |
| 779 | + | |
| 777 | 780 | # define VC4_DVP_HT_CLOCK_STOP_PIXEL BIT(1) |
| 778 | 781 | |
| 779 | 782 | /* HVS display list information. */ |
| @@ -248,6 +248,9 @@ void virtio_gpu_array_put_free(struct virtio_gpu_object_array *objs) · 247 unmodified lines | ||
| 248 | 248 | { |
| 249 | 249 | u32 i; |
| 250 | 250 | |
| 251 | + if (!objs) | |
| 252 | + return; | |
| 253 | + | |
| 251 | 254 | for (i = 0; i < objs->nents; i++) |
| 252 | 255 | drm_gem_object_put(objs->objs[i]); |
| 253 | 256 | virtio_gpu_array_free(objs); |
| @@ -20,6 +20,8 @@ · 19 unmodified lines | ||
| 20 | 20 | #define XRES_MAX 8192 |
| 21 | 21 | #define YRES_MAX 8192 |
| 22 | 22 | |
| 23 | +#define NUM_OVERLAY_PLANES 8 | |
| 24 | + | |
| 23 | 25 | struct vkms_writeback_job { |
| 24 | 26 | struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; |
| 25 | 27 | struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]; |
| @@ -32,6 +32,21 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = { · 31 unmodified lines | ||
| 32 | 32 | .get_modes = vkms_conn_get_modes, |
| 33 | 33 | }; |
| 34 | 34 | |
| 35 | +static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index, | |
| 36 | + struct drm_crtc *crtc) | |
| 37 | +{ | |
| 38 | + struct vkms_plane *overlay; | |
| 39 | + | |
| 40 | + overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index); | |
| 41 | + if (IS_ERR(overlay)) | |
| 42 | + return PTR_ERR(overlay); | |
| 43 | + | |
| 44 | + if (!overlay->base.possible_crtcs) | |
| 45 | + overlay->base.possible_crtcs = drm_crtc_mask(crtc); | |
| 46 | + | |
| 47 | + return 0; | |
| 48 | +} | |
| 49 | + | |
| 35 | 50 | int vkms_output_init(struct vkms_device *vkmsdev, int index) |
| 36 | 51 | { |
| 37 | 52 | struct vkms_output *output = &vkmsdev->output; |
| @@ -39,21 +54,21 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index) · 1 unmodified line | ||
| 39 | 54 | struct drm_connector *connector = &output->connector; |
| 40 | 55 | struct drm_encoder *encoder = &output->encoder; |
| 41 | 56 | struct drm_crtc *crtc = &output->crtc; |
| 42 | − struct vkms_plane *primary, *cursor = NULL, *overlay = NULL; | |
| 57 | + struct vkms_plane *primary, *cursor = NULL; | |
| 43 | 58 | int ret; |
| 44 | 59 | int writeback; |
| 60 | + unsigned int n; | |
| 45 | 61 | |
| 46 | 62 | primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, index); |
| 47 | 63 | if (IS_ERR(primary)) |
| 48 | 64 | return PTR_ERR(primary); |
| 49 | 65 | |
| 50 | 66 | if (vkmsdev->config->overlay) { |
| 51 | − overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index); | |
| 52 | − if (IS_ERR(overlay)) | |
| 53 | − return PTR_ERR(overlay); | |
| 54 | − | |
| 55 | − if (!overlay->base.possible_crtcs) | |
| 56 | − overlay->base.possible_crtcs = drm_crtc_mask(crtc); | |
| 67 | + for (n = 0; n < NUM_OVERLAY_PLANES; n++) { | |
| 68 | + ret = vkms_add_overlay_plane(vkmsdev, index, crtc); | |
| 69 | + if (ret) | |
| 70 | + return ret; | |
| 71 | + } | |
| 57 | 72 | } |
| 58 | 73 | |
| 59 | 74 | if (vkmsdev->config->cursor) { |
| @@ -117,6 +117,7 @@ nospace: · 116 unmodified lines | ||
| 117 | 117 | gman->used_gmr_pages -= (*res)->num_pages; |
| 118 | 118 | spin_unlock(&gman->lock); |
| 119 | 119 | ida_free(&gman->gmr_ida, id); |
| 120 | + ttm_resource_fini(man, *res); | |
| 120 | 121 | kfree(*res); |
| 121 | 122 | return -ENOSPC; |
| 122 | 123 | } |
| @@ -130,6 +131,7 @@ static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man, · 7 unmodified lines | ||
| 130 | 131 | spin_lock(&gman->lock); |
| 131 | 132 | gman->used_gmr_pages -= res->num_pages; |
| 132 | 133 | spin_unlock(&gman->lock); |
| 134 | + ttm_resource_fini(man, res); | |
| 133 | 135 | kfree(res); |
| 134 | 136 | } |
| 135 | 137 | |
| @@ -160,7 +162,7 @@ int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type) · 24 unmodified lines | ||
| 160 | 162 | |
| 161 | 163 | man->func = &vmw_gmrid_manager_func; |
| 162 | 164 | man->use_tt = true; |
| 163 | − ttm_resource_manager_init(man, 0); | |
| 165 | + ttm_resource_manager_init(man, &dev_priv->bdev, 0); | |
| 164 | 166 | spin_lock_init(&gman->lock); |
| 165 | 167 | gman->used_gmr_pages = 0; |
| 166 | 168 | ida_init(&gman->gmr_ida); |
| @@ -49,6 +49,7 @@ static int vmw_sys_man_alloc(struct ttm_resource_manager *man, · 48 unmodified lines | ||
| 49 | 49 | static void vmw_sys_man_free(struct ttm_resource_manager *man, |
| 50 | 50 | struct ttm_resource *res) |
| 51 | 51 | { |
| 52 | + ttm_resource_fini(man, res); | |
| 52 | 53 | kfree(res); |
| 53 | 54 | } |
| 54 | 55 | |
| @@ -69,7 +70,7 @@ int vmw_sys_man_init(struct vmw_private *dev_priv) · 14 unmodified lines | ||
| 69 | 70 | man->use_tt = true; |
| 70 | 71 | man->func = &vmw_sys_manager_func; |
| 71 | 72 | |
| 72 | − ttm_resource_manager_init(man, 0); | |
| 73 | + ttm_resource_manager_init(man, bdev, 0); | |
| 73 | 74 | ttm_set_driver_manager(bdev, VMW_PL_SYSTEM, man); |
| 74 | 75 | ttm_resource_manager_set_used(man, true); |
| 75 | 76 | return 0; |
| @@ -6,6 +6,7 @@ config DRM_ZYNQMP_DPSUB · 5 unmodified lines | ||
| 6 | 6 | depends on PHY_XILINX_ZYNQMP |
| 7 | 7 | depends on XILINX_ZYNQMP_DPDMA |
| 8 | 8 | select DMA_ENGINE |
| 9 | + select DRM_DP_HELPER | |
| 9 | 10 | select DRM_GEM_CMA_HELPER |
| 10 | 11 | select DRM_KMS_HELPER |
| 11 | 12 | select GENERIC_PHY |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <drm/drm_connector.h> |
| 14 | 14 | #include <drm/drm_crtc.h> |
| 15 | 15 | #include <drm/drm_device.h> |
| 16 | −#include <drm/drm_dp_helper.h> | |
| 16 | +#include <drm/dp/drm_dp_helper.h> | |
| 17 | 17 | #include <drm/drm_edid.h> |
| 18 | 18 | #include <drm/drm_encoder.h> |
| 19 | 19 | #include <drm/drm_managed.h> |
| @@ -243,6 +243,17 @@ config CROS_USBPD_NOTIFY · 242 unmodified lines | ||
| 243 | 243 | To compile this driver as a module, choose M here: the |
| 244 | 244 | module will be called cros_usbpd_notify. |
| 245 | 245 | |
| 246 | +config CHROMEOS_PRIVACY_SCREEN | |
| 247 | + tristate "ChromeOS Privacy Screen support" | |
| 248 | + depends on ACPI | |
| 249 | + depends on DRM | |
| 250 | + select DRM_PRIVACY_SCREEN | |
| 251 | + help | |
| 252 | + This driver provides the support needed for the in-built electronic | |
| 253 | + privacy screen that is present on some ChromeOS devices. When enabled, | |
| 254 | + this should probably always be built into the kernel to avoid or | |
| 255 | + minimize drm probe deferral. | |
| 256 | + | |
| 246 | 257 | source "drivers/platform/chrome/wilco_ec/Kconfig" |
| 247 | 258 | |
| 248 | 259 | endif # CHROMEOS_PLATFORMS |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | CFLAGS_cros_ec_trace.o:= -I$(src) |
| 5 | 5 | |
| 6 | 6 | obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o |
| 7 | +obj-$(CONFIG_CHROMEOS_PRIVACY_SCREEN) += chromeos_privacy_screen.o | |
| 7 | 8 | obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o |
| 8 | 9 | obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o |
| 9 | 10 | obj-$(CONFIG_CROS_EC) += cros_ec.o |
| @@ -0,0 +1,153 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +/* | |
| 4 | + * ChromeOS Privacy Screen support | |
| 5 | + * | |
| 6 | + * Copyright (C) 2022 Google LLC | |
| 7 | + * | |
| 8 | + * This is the Chromeos privacy screen provider, present on certain chromebooks, | |
| 9 | + * represented by a GOOG0010 device in the ACPI. This ACPI device, if present, | |
| 10 | + * will cause the i915 drm driver to probe defer until this driver registers | |
| 11 | + * the privacy-screen. | |
| 12 | + */ | |
| 13 | + | |
| 14 | +#include <linux/acpi.h> | |
| 15 | +#include <drm/drm_privacy_screen_driver.h> | |
| 16 | + | |
| 17 | +/* | |
| 18 | + * The DSM (Device Specific Method) constants below are the agreed API with | |
| 19 | + * the firmware team, on how to control privacy screen using ACPI methods. | |
| 20 | + */ | |
| 21 | +#define PRIV_SCRN_DSM_REVID 1 /* DSM version */ | |
| 22 | +#define PRIV_SCRN_DSM_FN_GET_STATUS 1 /* Get privacy screen status */ | |
| 23 | +#define PRIV_SCRN_DSM_FN_ENABLE 2 /* Enable privacy screen */ | |
| 24 | +#define PRIV_SCRN_DSM_FN_DISABLE 3 /* Disable privacy screen */ | |
| 25 | + | |
| 26 | +static const guid_t chromeos_privacy_screen_dsm_guid = | |
| 27 | + GUID_INIT(0xc7033113, 0x8720, 0x4ceb, | |
| 28 | + 0x90, 0x90, 0x9d, 0x52, 0xb3, 0xe5, 0x2d, 0x73); | |
| 29 | + | |
| 30 | +static void | |
| 31 | +chromeos_privacy_screen_get_hw_state(struct drm_privacy_screen | |
| 32 | + *drm_privacy_screen) | |
| 33 | +{ | |
| 34 | + union acpi_object *obj; | |
| 35 | + acpi_handle handle; | |
| 36 | + struct device *privacy_screen = | |
| 37 | + drm_privacy_screen_get_drvdata(drm_privacy_screen); | |
| 38 | + | |
| 39 | + handle = acpi_device_handle(to_acpi_device(privacy_screen)); | |
| 40 | + obj = acpi_evaluate_dsm(handle, &chromeos_privacy_screen_dsm_guid, | |
| 41 | + PRIV_SCRN_DSM_REVID, | |
| 42 | + PRIV_SCRN_DSM_FN_GET_STATUS, NULL); | |
| 43 | + if (!obj) { | |
| 44 | + dev_err(privacy_screen, | |
| 45 | + "_DSM failed to get privacy-screen state\n"); | |
| 46 | + return; | |
| 47 | + } | |
| 48 | + | |
| 49 | + if (obj->type != ACPI_TYPE_INTEGER) | |
| 50 | + dev_err(privacy_screen, | |
| 51 | + "Bad _DSM to get privacy-screen state\n"); | |
| 52 | + else if (obj->integer.value == 1) | |
| 53 | + drm_privacy_screen->hw_state = drm_privacy_screen->sw_state = | |
| 54 | + PRIVACY_SCREEN_ENABLED; | |
| 55 | + else | |
| 56 | + drm_privacy_screen->hw_state = drm_privacy_screen->sw_state = | |
| 57 | + PRIVACY_SCREEN_DISABLED; | |
| 58 | + | |
| 59 | + ACPI_FREE(obj); | |
| 60 | +} | |
| 61 | + | |
| 62 | +static int | |
| 63 | +chromeos_privacy_screen_set_sw_state(struct drm_privacy_screen | |
| 64 | + *drm_privacy_screen, | |
| 65 | + enum drm_privacy_screen_status state) | |
| 66 | +{ | |
| 67 | + union acpi_object *obj = NULL; | |
| 68 | + acpi_handle handle; | |
| 69 | + struct device *privacy_screen = | |
| 70 | + drm_privacy_screen_get_drvdata(drm_privacy_screen); | |
| 71 | + | |
| 72 | + handle = acpi_device_handle(to_acpi_device(privacy_screen)); | |
| 73 | + | |
| 74 | + if (state == PRIVACY_SCREEN_DISABLED) { | |
| 75 | + obj = acpi_evaluate_dsm(handle, | |
| 76 | + &chromeos_privacy_screen_dsm_guid, | |
| 77 | + PRIV_SCRN_DSM_REVID, | |
| 78 | + PRIV_SCRN_DSM_FN_DISABLE, NULL); | |
| 79 | + } else if (state == PRIVACY_SCREEN_ENABLED) { | |
| 80 | + obj = acpi_evaluate_dsm(handle, | |
| 81 | + &chromeos_privacy_screen_dsm_guid, | |
| 82 | + PRIV_SCRN_DSM_REVID, | |
| 83 | + PRIV_SCRN_DSM_FN_ENABLE, NULL); | |
| 84 | + } else { | |
| 85 | + dev_err(privacy_screen, | |
| 86 | + "Bad attempt to set privacy-screen status to %u\n", | |
| 87 | + state); | |
| 88 | + return -EINVAL; | |
| 89 | + } | |
| 90 | + | |
| 91 | + if (!obj) { | |
| 92 | + dev_err(privacy_screen, | |
| 93 | + "_DSM failed to set privacy-screen state\n"); | |
| 94 | + return -EIO; | |
| 95 | + } | |
| 96 | + | |
| 97 | + drm_privacy_screen->hw_state = drm_privacy_screen->sw_state = state; | |
| 98 | + ACPI_FREE(obj); | |
| 99 | + return 0; | |
| 100 | +} | |
| 101 | + | |
| 102 | +static const struct drm_privacy_screen_ops chromeos_privacy_screen_ops = { | |
| 103 | + .get_hw_state = chromeos_privacy_screen_get_hw_state, | |
| 104 | + .set_sw_state = chromeos_privacy_screen_set_sw_state, | |
| 105 | +}; | |
| 106 | + | |
| 107 | +static int chromeos_privacy_screen_add(struct acpi_device *adev) | |
| 108 | +{ | |
| 109 | + struct drm_privacy_screen *drm_privacy_screen = | |
| 110 | + drm_privacy_screen_register(&adev->dev, | |
| 111 | + &chromeos_privacy_screen_ops, | |
| 112 | + &adev->dev); | |
| 113 | + | |
| 114 | + if (IS_ERR(drm_privacy_screen)) { | |
| 115 | + dev_err(&adev->dev, "Error registering privacy-screen\n"); | |
| 116 | + return PTR_ERR(drm_privacy_screen); | |
| 117 | + } | |
| 118 | + | |
| 119 | + adev->driver_data = drm_privacy_screen; | |
| 120 | + dev_info(&adev->dev, "registered privacy-screen '%s'\n", | |
| 121 | + dev_name(&drm_privacy_screen->dev)); | |
| 122 | + | |
| 123 | + return 0; | |
| 124 | +} | |
| 125 | + | |
| 126 | +static int chromeos_privacy_screen_remove(struct acpi_device *adev) | |
| 127 | +{ | |
| 128 | + struct drm_privacy_screen *drm_privacy_screen = acpi_driver_data(adev); | |
| 129 | + | |
| 130 | + drm_privacy_screen_unregister(drm_privacy_screen); | |
| 131 | + return 0; | |
| 132 | +} | |
| 133 | + | |
| 134 | +static const struct acpi_device_id chromeos_privacy_screen_device_ids[] = { | |
| 135 | + {"GOOG0010", 0}, /* Google's electronic privacy screen for eDP-1 */ | |
| 136 | + {} | |
| 137 | +}; | |
| 138 | +MODULE_DEVICE_TABLE(acpi, chromeos_privacy_screen_device_ids); | |
| 139 | + | |
| 140 | +static struct acpi_driver chromeos_privacy_screen_driver = { | |
| 141 | + .name = "chromeos_privacy_screen_driver", | |
| 142 | + .class = "ChromeOS", | |
| 143 | + .ids = chromeos_privacy_screen_device_ids, | |
| 144 | + .ops = { | |
| 145 | + .add = chromeos_privacy_screen_add, | |
| 146 | + .remove = chromeos_privacy_screen_remove, | |
| 147 | + }, | |
| 148 | +}; | |
| 149 | + | |
| 150 | +module_acpi_driver(chromeos_privacy_screen_driver); | |
| 151 | +MODULE_LICENSE("GPL v2"); | |
| 152 | +MODULE_DESCRIPTION("ChromeOS ACPI Privacy Screen driver"); | |
| 153 | +MODULE_AUTHOR("Rajat Jain <rajatja@google.com>"); | |
| @@ -9869,7 +9869,7 @@ static int tpacpi_lcdshadow_init(struct ibm_init_struct *iibm) · 9868 unmodified lines | ||
| 9869 | 9869 | return 0; |
| 9870 | 9870 | |
| 9871 | 9871 | lcdshadow_dev = drm_privacy_screen_register(&tpacpi_pdev->dev, |
| 9872 | − &lcdshadow_ops); | |
| 9872 | + &lcdshadow_ops, NULL); | |
| 9873 | 9873 | if (IS_ERR(lcdshadow_dev)) |
| 9874 | 9874 | return PTR_ERR(lcdshadow_dev); |
| 9875 | 9875 | |
| @@ -110,7 +110,7 @@ static const struct fb_ops asiliantfb_ops = { · 109 unmodified lines | ||
| 110 | 110 | static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dclk2_div) |
| 111 | 111 | { |
| 112 | 112 | unsigned pixclock = *ppixclock; |
| 113 | − unsigned Ftarget = 1000000 * (1000000 / pixclock); | |
| 113 | + unsigned Ftarget; | |
| 114 | 114 | unsigned n; |
| 115 | 115 | unsigned best_error = 0xffffffff; |
| 116 | 116 | unsigned best_m = 0xffffffff, |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <linux/init.h> |
| 26 | 26 | #include <linux/linux_logo.h> |
| 27 | 27 | #include <linux/proc_fs.h> |
| 28 | +#include <linux/platform_device.h> | |
| 28 | 29 | #include <linux/seq_file.h> |
| 29 | 30 | #include <linux/console.h> |
| 30 | 31 | #include <linux/kmod.h> |
| @@ -1557,18 +1558,36 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a, · 1526 unmodified lines | ||
| 1557 | 1558 | /* check all firmware fbs and kick off if the base addr overlaps */ |
| 1558 | 1559 | for_each_registered_fb(i) { |
| 1559 | 1560 | struct apertures_struct *gen_aper; |
| 1561 | + struct device *device; | |
| 1560 | 1562 | |
| 1561 | 1563 | if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) |
| 1562 | 1564 | continue; |
| 1563 | 1565 | |
| 1564 | 1566 | gen_aper = registered_fb[i]->apertures; |
| 1567 | + device = registered_fb[i]->device; | |
| 1565 | 1568 | if (fb_do_apertures_overlap(gen_aper, a) || |
| 1566 | 1569 | (primary && gen_aper && gen_aper->count && |
| 1567 | 1570 | gen_aper->ranges[0].base == VGA_FB_PHYS)) { |
| 1568 | 1571 | |
| 1569 | 1572 | printk(KERN_INFO "fb%d: switching to %s from %s\n", |
| 1570 | 1573 | i, name, registered_fb[i]->fix.id); |
| 1571 | − do_unregister_framebuffer(registered_fb[i]); | |
| 1574 | + | |
| 1575 | + /* | |
| 1576 | + * If we kick-out a firmware driver, we also want to remove | |
| 1577 | + * the underlying platform device, such as simple-framebuffer, | |
| 1578 | + * VESA, EFI, etc. A native driver will then be able to | |
| 1579 | + * allocate the memory range. | |
| 1580 | + * | |
| 1581 | + * If it's not a platform device, at least print a warning. A | |
| 1582 | + * fix would add code to remove the device from the system. | |
| 1583 | + */ | |
| 1584 | + if (dev_is_platform(device)) { | |
| 1585 | + registered_fb[i]->forced_out = true; | |
| 1586 | + platform_device_unregister(to_platform_device(device)); | |
| 1587 | + } else { | |
| 1588 | + pr_warn("fb%d: cannot remove device\n", i); | |
| 1589 | + do_unregister_framebuffer(registered_fb[i]); | |
| 1590 | + } | |
| 1572 | 1591 | } |
| 1573 | 1592 | } |
| 1574 | 1593 | } |
| @@ -1898,9 +1917,13 @@ EXPORT_SYMBOL(register_framebuffer); · 323 unmodified lines | ||
| 1898 | 1917 | void |
| 1899 | 1918 | unregister_framebuffer(struct fb_info *fb_info) |
| 1900 | 1919 | { |
| 1901 | − mutex_lock(®istration_lock); | |
| 1920 | + bool forced_out = fb_info->forced_out; | |
| 1921 | + | |
| 1922 | + if (!forced_out) | |
| 1923 | + mutex_lock(®istration_lock); | |
| 1902 | 1924 | do_unregister_framebuffer(fb_info); |
| 1903 | − mutex_unlock(®istration_lock); | |
| 1925 | + if (!forced_out) | |
| 1926 | + mutex_unlock(®istration_lock); | |
| 1904 | 1927 | } |
| 1905 | 1928 | EXPORT_SYMBOL(unregister_framebuffer); |
| 1906 | 1929 | |
| @@ -489,7 +489,7 @@ static int s3c_fb_set_par(struct fb_info *info) · 488 unmodified lines | ||
| 489 | 489 | struct s3c_fb_win *win = info->par; |
| 490 | 490 | struct s3c_fb *sfb = win->parent; |
| 491 | 491 | void __iomem *regs = sfb->regs; |
| 492 | − void __iomem *buf = regs; | |
| 492 | + void __iomem *buf; | |
| 493 | 493 | int win_no = win->index; |
| 494 | 494 | u32 alpha = 0; |
| 495 | 495 | u32 data; |
| @@ -66,16 +66,36 @@ static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, · 65 unmodified lines | ||
| 66 | 66 | return 0; |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | −struct simplefb_par; | |
| 69 | +struct simplefb_par { | |
| 70 | + u32 palette[PSEUDO_PALETTE_SIZE]; | |
| 71 | + struct resource *mem; | |
| 72 | +#if defined CONFIG_OF && defined CONFIG_COMMON_CLK | |
| 73 | + bool clks_enabled; | |
| 74 | + unsigned int clk_count; | |
| 75 | + struct clk **clks; | |
| 76 | +#endif | |
| 77 | +#if defined CONFIG_OF && defined CONFIG_REGULATOR | |
| 78 | + bool regulators_enabled; | |
| 79 | + u32 regulator_count; | |
| 80 | + struct regulator **regulators; | |
| 81 | +#endif | |
| 82 | +}; | |
| 83 | + | |
| 70 | 84 | static void simplefb_clocks_destroy(struct simplefb_par *par); |
| 71 | 85 | static void simplefb_regulators_destroy(struct simplefb_par *par); |
| 72 | 86 | |
| 73 | 87 | static void simplefb_destroy(struct fb_info *info) |
| 74 | 88 | { |
| 89 | + struct simplefb_par *par = info->par; | |
| 90 | + struct resource *mem = par->mem; | |
| 91 | + | |
| 75 | 92 | simplefb_regulators_destroy(info->par); |
| 76 | 93 | simplefb_clocks_destroy(info->par); |
| 77 | 94 | if (info->screen_base) |
| 78 | 95 | iounmap(info->screen_base); |
| 96 | + | |
| 97 | + if (mem) | |
| 98 | + release_mem_region(mem->start, resource_size(mem)); | |
| 79 | 99 | } |
| 80 | 100 | |
| 81 | 101 | static const struct fb_ops simplefb_ops = { |
| @@ -169,20 +189,6 @@ static int simplefb_parse_pd(struct platform_device *pdev, · 87 unmodified lines | ||
| 169 | 189 | return 0; |
| 170 | 190 | } |
| 171 | 191 | |
| 172 | −struct simplefb_par { | |
| 173 | − u32 palette[PSEUDO_PALETTE_SIZE]; | |
| 174 | −#if defined CONFIG_OF && defined CONFIG_COMMON_CLK | |
| 175 | − bool clks_enabled; | |
| 176 | − unsigned int clk_count; | |
| 177 | − struct clk **clks; | |
| 178 | −#endif | |
| 179 | −#if defined CONFIG_OF && defined CONFIG_REGULATOR | |
| 180 | − bool regulators_enabled; | |
| 181 | − u32 regulator_count; | |
| 182 | − struct regulator **regulators; | |
| 183 | −#endif | |
| 184 | −}; | |
| 185 | − | |
| 186 | 192 | #if defined CONFIG_OF && defined CONFIG_COMMON_CLK |
| 187 | 193 | /* |
| 188 | 194 | * Clock handling code. |
| @@ -405,7 +411,7 @@ static int simplefb_probe(struct platform_device *pdev) · 216 unmodified lines | ||
| 405 | 411 | struct simplefb_params params; |
| 406 | 412 | struct fb_info *info; |
| 407 | 413 | struct simplefb_par *par; |
| 408 | − struct resource *mem; | |
| 414 | + struct resource *res, *mem; | |
| 409 | 415 | |
| 410 | 416 | /* |
| 411 | 417 | * Generic drivers must not be registered if a framebuffer exists. |
| @@ -430,15 +436,28 @@ static int simplefb_probe(struct platform_device *pdev) · 18 unmodified lines | ||
| 430 | 436 | if (ret) |
| 431 | 437 | return ret; |
| 432 | 438 | |
| 433 | − mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 434 | − if (!mem) { | |
| 439 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 440 | + if (!res) { | |
| 435 | 441 | dev_err(&pdev->dev, "No memory resource\n"); |
| 436 | 442 | return -EINVAL; |
| 437 | 443 | } |
| 438 | 444 | |
| 445 | + mem = request_mem_region(res->start, resource_size(res), "simplefb"); | |
| 446 | + if (!mem) { | |
| 447 | + /* | |
| 448 | + * We cannot make this fatal. Sometimes this comes from magic | |
| 449 | + * spaces our resource handlers simply don't know about. Use | |
| 450 | + * the I/O-memory resource as-is and try to map that instead. | |
| 451 | + */ | |
| 452 | + dev_warn(&pdev->dev, "simplefb: cannot reserve video memory at %pR\n", res); | |
| 453 | + mem = res; | |
| 454 | + } | |
| 455 | + | |
| 439 | 456 | info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev); |
| 440 | − if (!info) | |
| 441 | − return -ENOMEM; | |
| 457 | + if (!info) { | |
| 458 | + ret = -ENOMEM; | |
| 459 | + goto error_release_mem_region; | |
| 460 | + } | |
| 442 | 461 | platform_set_drvdata(pdev, info); |
| 443 | 462 | |
| 444 | 463 | par = info->par; |
| @@ -495,6 +514,9 @@ static int simplefb_probe(struct platform_device *pdev) · 50 unmodified lines | ||
| 495 | 514 | info->var.xres, info->var.yres, |
| 496 | 515 | info->var.bits_per_pixel, info->fix.line_length); |
| 497 | 516 | |
| 517 | + if (mem != res) | |
| 518 | + par->mem = mem; /* release in clean-up handler */ | |
| 519 | + | |
| 498 | 520 | ret = register_framebuffer(info); |
| 499 | 521 | if (ret < 0) { |
| 500 | 522 | dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); |
| @@ -513,6 +535,9 @@ error_unmap: · 12 unmodified lines | ||
| 513 | 535 | iounmap(info->screen_base); |
| 514 | 536 | error_fb_release: |
| 515 | 537 | framebuffer_release(info); |
| 538 | +error_release_mem_region: | |
| 539 | + if (mem != res) | |
| 540 | + release_mem_region(mem->start, resource_size(mem)); | |
| 516 | 541 | return ret; |
| 517 | 542 | } |
| 518 | 543 | |
| @@ -1351,7 +1351,12 @@ static int vga16fb_probe(struct platform_device *dev) · 1350 unmodified lines | ||
| 1351 | 1351 | printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base); |
| 1352 | 1352 | par = info->par; |
| 1353 | 1353 | |
| 1354 | +#if defined(CONFIG_X86) | |
| 1355 | + par->isVGA = screen_info.orig_video_isVGA == VIDEO_TYPE_VGAC; | |
| 1356 | +#else | |
| 1357 | + /* non-x86 architectures treat orig_video_isVGA as a boolean flag */ | |
| 1354 | 1358 | par->isVGA = screen_info.orig_video_isVGA; |
| 1359 | +#endif | |
| 1355 | 1360 | par->palette_blanked = 0; |
| 1356 | 1361 | par->vesa_blanked = 0; |
| 1357 | 1362 | |
| @@ -51,7 +51,9 @@ struct dw_mipi_dsi_plat_data { · 50 unmodified lines | ||
| 51 | 51 | unsigned int max_data_lanes; |
| 52 | 52 | |
| 53 | 53 | enum drm_mode_status (*mode_valid)(void *priv_data, |
| 54 | − const struct drm_display_mode *mode); | |
| 54 | + const struct drm_display_mode *mode, | |
| 55 | + unsigned long mode_flags, | |
| 56 | + u32 lanes, u32 format); | |
| 55 | 57 | |
| 56 | 58 | const struct dw_mipi_dsi_phy_ops *phy_ops; |
| 57 | 59 | const struct dw_mipi_dsi_host_ops *host_ops; |
File renamed without changes.
File renamed without changes.
| @@ -1038,11 +1038,8 @@ struct drm_panel; · 1037 unmodified lines | ||
| 1038 | 1038 | #define DP_SIDEBAND_MSG_UP_REQ_BASE 0x1600 /* 1.2 MST */ |
| 1039 | 1039 | |
| 1040 | 1040 | /* DPRX Event Status Indicator */ |
| 1041 | −#define DP_SINK_COUNT_ESI 0x2002 /* 1.2 */ | |
| 1042 | −/* 0-5 sink count */ | |
| 1043 | −# define DP_SINK_COUNT_CP_READY (1 << 6) | |
| 1044 | − | |
| 1045 | −#define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x2003 /* 1.2 */ | |
| 1041 | +#define DP_SINK_COUNT_ESI 0x2002 /* same as 0x200 */ | |
| 1042 | +#define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x2003 /* same as 0x201 */ | |
| 1046 | 1043 | |
| 1047 | 1044 | #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 0x2004 /* 1.2 */ |
| 1048 | 1045 | # define DP_RX_GTC_MSTR_REQ_STATUS_CHANGE (1 << 0) |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #define _DRM_DP_MST_HELPER_H_ |
| 24 | 24 | |
| 25 | 25 | #include <linux/types.h> |
| 26 | −#include <drm/drm_dp_helper.h> | |
| 26 | +#include <drm/dp/drm_dp_helper.h> | |
| 27 | 27 | #include <drm/drm_atomic.h> |
| 28 | 28 | |
| 29 | 29 | #if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) |
| @@ -0,0 +1,150 @@ | ||
| 1 | +/* SPDX-License-Identifier: MIT */ | |
| 2 | +/* | |
| 3 | + * Copyright © 2021 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#ifndef __DRM_BUDDY_H__ | |
| 7 | +#define __DRM_BUDDY_H__ | |
| 8 | + | |
| 9 | +#include <linux/bitops.h> | |
| 10 | +#include <linux/list.h> | |
| 11 | +#include <linux/slab.h> | |
| 12 | +#include <linux/sched.h> | |
| 13 | + | |
| 14 | +#include <drm/drm_print.h> | |
| 15 | + | |
| 16 | +#define range_overflows(start, size, max) ({ \ | |
| 17 | + typeof(start) start__ = (start); \ | |
| 18 | + typeof(size) size__ = (size); \ | |
| 19 | + typeof(max) max__ = (max); \ | |
| 20 | + (void)(&start__ == &size__); \ | |
| 21 | + (void)(&start__ == &max__); \ | |
| 22 | + start__ >= max__ || size__ > max__ - start__; \ | |
| 23 | +}) | |
| 24 | + | |
| 25 | +struct drm_buddy_block { | |
| 26 | +#define DRM_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) | |
| 27 | +#define DRM_BUDDY_HEADER_STATE GENMASK_ULL(11, 10) | |
| 28 | +#define DRM_BUDDY_ALLOCATED (1 << 10) | |
| 29 | +#define DRM_BUDDY_FREE (2 << 10) | |
| 30 | +#define DRM_BUDDY_SPLIT (3 << 10) | |
| 31 | +/* Free to be used, if needed in the future */ | |
| 32 | +#define DRM_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6) | |
| 33 | +#define DRM_BUDDY_HEADER_ORDER GENMASK_ULL(5, 0) | |
| 34 | + u64 header; | |
| 35 | + | |
| 36 | + struct drm_buddy_block *left; | |
| 37 | + struct drm_buddy_block *right; | |
| 38 | + struct drm_buddy_block *parent; | |
| 39 | + | |
| 40 | + void *private; /* owned by creator */ | |
| 41 | + | |
| 42 | + /* | |
| 43 | + * While the block is allocated by the user through drm_buddy_alloc*, | |
| 44 | + * the user has ownership of the link, for example to maintain within | |
| 45 | + * a list, if so desired. As soon as the block is freed with | |
| 46 | + * drm_buddy_free* ownership is given back to the mm. | |
| 47 | + */ | |
| 48 | + struct list_head link; | |
| 49 | + struct list_head tmp_link; | |
| 50 | +}; | |
| 51 | + | |
| 52 | +/* Order-zero must be at least PAGE_SIZE */ | |
| 53 | +#define DRM_BUDDY_MAX_ORDER (63 - PAGE_SHIFT) | |
| 54 | + | |
| 55 | +/* | |
| 56 | + * Binary Buddy System. | |
| 57 | + * | |
| 58 | + * Locking should be handled by the user, a simple mutex around | |
| 59 | + * drm_buddy_alloc* and drm_buddy_free* should suffice. | |
| 60 | + */ | |
| 61 | +struct drm_buddy { | |
| 62 | + /* Maintain a free list for each order. */ | |
| 63 | + struct list_head *free_list; | |
| 64 | + | |
| 65 | + /* | |
| 66 | + * Maintain explicit binary tree(s) to track the allocation of the | |
| 67 | + * address space. This gives us a simple way of finding a buddy block | |
| 68 | + * and performing the potentially recursive merge step when freeing a | |
| 69 | + * block. Nodes are either allocated or free, in which case they will | |
| 70 | + * also exist on the respective free list. | |
| 71 | + */ | |
| 72 | + struct drm_buddy_block **roots; | |
| 73 | + | |
| 74 | + /* | |
| 75 | + * Anything from here is public, and remains static for the lifetime of | |
| 76 | + * the mm. Everything above is considered do-not-touch. | |
| 77 | + */ | |
| 78 | + unsigned int n_roots; | |
| 79 | + unsigned int max_order; | |
| 80 | + | |
| 81 | + /* Must be at least PAGE_SIZE */ | |
| 82 | + u64 chunk_size; | |
| 83 | + u64 size; | |
| 84 | + u64 avail; | |
| 85 | +}; | |
| 86 | + | |
| 87 | +static inline u64 | |
| 88 | +drm_buddy_block_offset(struct drm_buddy_block *block) | |
| 89 | +{ | |
| 90 | + return block->header & DRM_BUDDY_HEADER_OFFSET; | |
| 91 | +} | |
| 92 | + | |
| 93 | +static inline unsigned int | |
| 94 | +drm_buddy_block_order(struct drm_buddy_block *block) | |
| 95 | +{ | |
| 96 | + return block->header & DRM_BUDDY_HEADER_ORDER; | |
| 97 | +} | |
| 98 | + | |
| 99 | +static inline unsigned int | |
| 100 | +drm_buddy_block_state(struct drm_buddy_block *block) | |
| 101 | +{ | |
| 102 | + return block->header & DRM_BUDDY_HEADER_STATE; | |
| 103 | +} | |
| 104 | + | |
| 105 | +static inline bool | |
| 106 | +drm_buddy_block_is_allocated(struct drm_buddy_block *block) | |
| 107 | +{ | |
| 108 | + return drm_buddy_block_state(block) == DRM_BUDDY_ALLOCATED; | |
| 109 | +} | |
| 110 | + | |
| 111 | +static inline bool | |
| 112 | +drm_buddy_block_is_free(struct drm_buddy_block *block) | |
| 113 | +{ | |
| 114 | + return drm_buddy_block_state(block) == DRM_BUDDY_FREE; | |
| 115 | +} | |
| 116 | + | |
| 117 | +static inline bool | |
| 118 | +drm_buddy_block_is_split(struct drm_buddy_block *block) | |
| 119 | +{ | |
| 120 | + return drm_buddy_block_state(block) == DRM_BUDDY_SPLIT; | |
| 121 | +} | |
| 122 | + | |
| 123 | +static inline u64 | |
| 124 | +drm_buddy_block_size(struct drm_buddy *mm, | |
| 125 | + struct drm_buddy_block *block) | |
| 126 | +{ | |
| 127 | + return mm->chunk_size << drm_buddy_block_order(block); | |
| 128 | +} | |
| 129 | + | |
| 130 | +int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size); | |
| 131 | + | |
| 132 | +void drm_buddy_fini(struct drm_buddy *mm); | |
| 133 | + | |
| 134 | +struct drm_buddy_block * | |
| 135 | +drm_buddy_alloc_blocks(struct drm_buddy *mm, unsigned int order); | |
| 136 | + | |
| 137 | +int drm_buddy_alloc_range(struct drm_buddy *mm, | |
| 138 | + struct list_head *blocks, | |
| 139 | + u64 start, u64 size); | |
| 140 | + | |
| 141 | +void drm_buddy_free_block(struct drm_buddy *mm, struct drm_buddy_block *block); | |
| 142 | + | |
| 143 | +void drm_buddy_free_list(struct drm_buddy *mm, struct list_head *objects); | |
| 144 | + | |
| 145 | +void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p); | |
| 146 | +void drm_buddy_block_print(struct drm_buddy *mm, | |
| 147 | + struct drm_buddy_block *block, | |
| 148 | + struct drm_printer *p); | |
| 149 | + | |
| 150 | +#endif | |
| @@ -522,9 +522,9 @@ struct drm_display_info { · 521 unmodified lines | ||
| 522 | 522 | enum subpixel_order subpixel_order; |
| 523 | 523 | |
| 524 | 524 | #define DRM_COLOR_FORMAT_RGB444 (1<<0) |
| 525 | −#define DRM_COLOR_FORMAT_YCRCB444 (1<<1) | |
| 526 | −#define DRM_COLOR_FORMAT_YCRCB422 (1<<2) | |
| 527 | −#define DRM_COLOR_FORMAT_YCRCB420 (1<<3) | |
| 525 | +#define DRM_COLOR_FORMAT_YCBCR444 (1<<1) | |
| 526 | +#define DRM_COLOR_FORMAT_YCBCR422 (1<<2) | |
| 527 | +#define DRM_COLOR_FORMAT_YCBCR420 (1<<3) | |
| 528 | 528 | |
| 529 | 529 | /** |
| 530 | 530 | * @panel_orientation: Read only connector property for built-in panels, |
| @@ -592,10 +592,16 @@ struct drm_display_info { · 61 unmodified lines | ||
| 592 | 592 | bool rgb_quant_range_selectable; |
| 593 | 593 | |
| 594 | 594 | /** |
| 595 | − * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even | |
| 596 | − * more stuff redundant with @bus_formats. | |
| 595 | + * @edid_hdmi_dc_rgb444_modes: Mask of supported hdmi deep color modes | |
| 596 | + * in RGB 4:4:4. Even more stuff redundant with @bus_formats. | |
| 597 | 597 | */ |
| 598 | − u8 edid_hdmi_dc_modes; | |
| 598 | + u8 edid_hdmi_rgb444_dc_modes; | |
| 599 | + | |
| 600 | + /** | |
| 601 | + * @edid_hdmi_dc_ycbcr444_modes: Mask of supported hdmi deep color | |
| 602 | + * modes in YCbCr 4:4:4. Even more stuff redundant with @bus_formats. | |
| 603 | + */ | |
| 604 | + u8 edid_hdmi_ycbcr444_dc_modes; | |
| 599 | 605 | |
| 600 | 606 | /** |
| 601 | 607 | * @cea_rev: CEA revision of the HDMI sink. |
| @@ -285,6 +285,10 @@ struct drm_crtc_state { · 284 unmodified lines | ||
| 285 | 285 | * Lookup table for converting pixel data after the color conversion |
| 286 | 286 | * matrix @ctm. See drm_crtc_enable_color_mgmt(). The blob (if not |
| 287 | 287 | * NULL) is an array of &struct drm_color_lut. |
| 288 | + * | |
| 289 | + * Note that for mostly historical reasons stemming from Xorg heritage, | |
| 290 | + * this is also used to store the color map (also sometimes color lut, | |
| 291 | + * CLUT or color palette) for indexed formats like DRM_FORMAT_C8. | |
| 288 | 292 | */ |
| 289 | 293 | struct drm_property_blob *gamma_lut; |
| 290 | 294 | |
| @@ -1075,12 +1079,18 @@ struct drm_crtc { · 784 unmodified lines | ||
| 1075 | 1079 | /** |
| 1076 | 1080 | * @gamma_size: Size of legacy gamma ramp reported to userspace. Set up |
| 1077 | 1081 | * by calling drm_mode_crtc_set_gamma_size(). |
| 1082 | + * | |
| 1083 | + * Note that atomic drivers need to instead use | |
| 1084 | + * &drm_crtc_state.gamma_lut. See drm_crtc_enable_color_mgmt(). | |
| 1078 | 1085 | */ |
| 1079 | 1086 | uint32_t gamma_size; |
| 1080 | 1087 | |
| 1081 | 1088 | /** |
| 1082 | 1089 | * @gamma_store: Gamma ramp values used by the legacy SETGAMMA and |
| 1083 | 1090 | * GETGAMMA IOCTls. Set up by calling drm_mode_crtc_set_gamma_size(). |
| 1091 | + * | |
| 1092 | + * Note that atomic drivers need to instead use | |
| 1093 | + * &drm_crtc_state.gamma_lut. See drm_crtc_enable_color_mgmt(). | |
| 1084 | 1094 | */ |
| 1085 | 1095 | uint16_t *gamma_store; |
| 1086 | 1096 | |
| @@ -8,7 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | #ifndef DRM_DSC_H_ |
| 9 | 9 | #define DRM_DSC_H_ |
| 10 | 10 | |
| 11 | −#include <drm/drm_dp_helper.h> | |
| 11 | +#include <drm/dp/drm_dp_helper.h> | |
| 12 | 12 | |
| 13 | 13 | /* VESA Display Stream Compression DSC 1.2 constants */ |
| 14 | 14 | #define DSC_NUM_BUF_RANGES 15 |
| @@ -401,8 +401,8 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, · 400 unmodified lines | ||
| 401 | 401 | const struct drm_display_mode *mode); |
| 402 | 402 | |
| 403 | 403 | void |
| 404 | −drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, | |
| 405 | − const struct drm_connector_state *conn_state); | |
| 404 | +drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, | |
| 405 | + const struct drm_connector_state *conn_state); | |
| 406 | 406 | |
| 407 | 407 | void |
| 408 | 408 | drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, |
| @@ -194,7 +194,7 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, · 193 unmodified lines | ||
| 194 | 194 | #ifdef CONFIG_DEBUG_FS |
| 195 | 195 | void mipi_dbi_debugfs_init(struct drm_minor *minor); |
| 196 | 196 | #else |
| 197 | −#define mipi_dbi_debugfs_init NULL | |
| 197 | +static inline void mipi_dbi_debugfs_init(struct drm_minor *minor) {} | |
| 198 | 198 | #endif |
| 199 | 199 | |
| 200 | 200 | #endif /* __LINUX_MIPI_DBI_H */ |
| @@ -34,6 +34,7 @@ struct drm_modeset_lock; · 33 unmodified lines | ||
| 34 | 34 | * struct drm_modeset_acquire_ctx - locking context (see ww_acquire_ctx) |
| 35 | 35 | * @ww_ctx: base acquire ctx |
| 36 | 36 | * @contended: used internally for -EDEADLK handling |
| 37 | + * @stack_depot: used internally for contention debugging | |
| 37 | 38 | * @locked: list of held locks |
| 38 | 39 | * @trylock_only: trylock mode used in atomic contexts/panic notifiers |
| 39 | 40 | * @interruptible: whether interruptible locking should be used. |
| @@ -0,0 +1,125 @@ | ||
| 1 | +/* SPDX-License-Identifier: MIT */ | |
| 2 | + | |
| 3 | +#ifndef DRM_MODULE_H | |
| 4 | +#define DRM_MODULE_H | |
| 5 | + | |
| 6 | +#include <linux/pci.h> | |
| 7 | +#include <linux/platform_device.h> | |
| 8 | + | |
| 9 | +#include <drm/drm_drv.h> | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * DOC: overview | |
| 13 | + * | |
| 14 | + * This library provides helpers registering DRM drivers during module | |
| 15 | + * initialization and shutdown. The provided helpers act like bus-specific | |
| 16 | + * module helpers, such as module_pci_driver(), but respect additional | |
| 17 | + * parameters that control DRM driver registration. | |
| 18 | + * | |
| 19 | + * Below is an example of initializing a DRM driver for a device on the | |
| 20 | + * PCI bus. | |
| 21 | + * | |
| 22 | + * .. code-block:: c | |
| 23 | + * | |
| 24 | + * struct pci_driver my_pci_drv = { | |
| 25 | + * }; | |
| 26 | + * | |
| 27 | + * drm_module_pci_driver(my_pci_drv); | |
| 28 | + * | |
| 29 | + * The generated code will test if DRM drivers are enabled and register | |
| 30 | + * the PCI driver my_pci_drv. For more complex module initialization, you | |
| 31 | + * can still use module_init() and module_exit() in your driver. | |
| 32 | + */ | |
| 33 | + | |
| 34 | +/* | |
| 35 | + * PCI drivers | |
| 36 | + */ | |
| 37 | + | |
| 38 | +static inline int __init drm_pci_register_driver(struct pci_driver *pci_drv) | |
| 39 | +{ | |
| 40 | + if (drm_firmware_drivers_only()) | |
| 41 | + return -ENODEV; | |
| 42 | + | |
| 43 | + return pci_register_driver(pci_drv); | |
| 44 | +} | |
| 45 | + | |
| 46 | +/** | |
| 47 | + * drm_module_pci_driver - Register a DRM driver for PCI-based devices | |
| 48 | + * @__pci_drv: the PCI driver structure | |
| 49 | + * | |
| 50 | + * Registers a DRM driver for devices on the PCI bus. The helper | |
| 51 | + * macro behaves like module_pci_driver() but tests the state of | |
| 52 | + * drm_firmware_drivers_only(). For more complex module initialization, | |
| 53 | + * use module_init() and module_exit() directly. | |
| 54 | + * | |
| 55 | + * Each module may only use this macro once. Calling it replaces | |
| 56 | + * module_init() and module_exit(). | |
| 57 | + */ | |
| 58 | +#define drm_module_pci_driver(__pci_drv) \ | |
| 59 | + module_driver(__pci_drv, drm_pci_register_driver, pci_unregister_driver) | |
| 60 | + | |
| 61 | +static inline int __init | |
| 62 | +drm_pci_register_driver_if_modeset(struct pci_driver *pci_drv, int modeset) | |
| 63 | +{ | |
| 64 | + if (drm_firmware_drivers_only() && modeset == -1) | |
| 65 | + return -ENODEV; | |
| 66 | + if (modeset == 0) | |
| 67 | + return -ENODEV; | |
| 68 | + | |
| 69 | + return pci_register_driver(pci_drv); | |
| 70 | +} | |
| 71 | + | |
| 72 | +static inline void __exit | |
| 73 | +drm_pci_unregister_driver_if_modeset(struct pci_driver *pci_drv, int modeset) | |
| 74 | +{ | |
| 75 | + pci_unregister_driver(pci_drv); | |
| 76 | +} | |
| 77 | + | |
| 78 | +/** | |
| 79 | + * drm_module_pci_driver_if_modeset - Register a DRM driver for PCI-based devices | |
| 80 | + * @__pci_drv: the PCI driver structure | |
| 81 | + * @__modeset: an additional parameter that disables the driver | |
| 82 | + * | |
| 83 | + * This macro is deprecated and only provided for existing drivers. For | |
| 84 | + * new drivers, use drm_module_pci_driver(). | |
| 85 | + * | |
| 86 | + * Registers a DRM driver for devices on the PCI bus. The helper macro | |
| 87 | + * behaves like drm_module_pci_driver() with an additional driver-specific | |
| 88 | + * flag. If __modeset is 0, the driver has been disabled, if __modeset is | |
| 89 | + * -1 the driver state depends on the global DRM state. For all other | |
| 90 | + * values, the PCI driver has been enabled. The default should be -1. | |
| 91 | + */ | |
| 92 | +#define drm_module_pci_driver_if_modeset(__pci_drv, __modeset) \ | |
| 93 | + module_driver(__pci_drv, drm_pci_register_driver_if_modeset, \ | |
| 94 | + drm_pci_unregister_driver_if_modeset, __modeset) | |
| 95 | + | |
| 96 | +/* | |
| 97 | + * Platform drivers | |
| 98 | + */ | |
| 99 | + | |
| 100 | +static inline int __init | |
| 101 | +drm_platform_driver_register(struct platform_driver *platform_drv) | |
| 102 | +{ | |
| 103 | + if (drm_firmware_drivers_only()) | |
| 104 | + return -ENODEV; | |
| 105 | + | |
| 106 | + return platform_driver_register(platform_drv); | |
| 107 | +} | |
| 108 | + | |
| 109 | +/** | |
| 110 | + * drm_module_platform_driver - Register a DRM driver for platform devices | |
| 111 | + * @__platform_drv: the platform driver structure | |
| 112 | + * | |
| 113 | + * Registers a DRM driver for devices on the platform bus. The helper | |
| 114 | + * macro behaves like module_platform_driver() but tests the state of | |
| 115 | + * drm_firmware_drivers_only(). For more complex module initialization, | |
| 116 | + * use module_init() and module_exit() directly. | |
| 117 | + * | |
| 118 | + * Each module may only use this macro once. Calling it replaces | |
| 119 | + * module_init() and module_exit(). | |
| 120 | + */ | |
| 121 | +#define drm_module_platform_driver(__platform_drv) \ | |
| 122 | + module_driver(__platform_drv, drm_platform_driver_register, \ | |
| 123 | + platform_driver_unregister) | |
| 124 | + | |
| 125 | +#endif | |
| @@ -516,7 +516,7 @@ struct drm_plane_funcs { · 515 unmodified lines | ||
| 516 | 516 | * This optional hook is used for the DRM to determine if the given |
| 517 | 517 | * format/modifier combination is valid for the plane. This allows the |
| 518 | 518 | * DRM to generate the correct format bitmask (which formats apply to |
| 519 | − * which modifier), and to valdiate modifiers at atomic_check time. | |
| 519 | + * which modifier), and to validate modifiers at atomic_check time. | |
| 520 | 520 | * |
| 521 | 521 | * If not present, then any modifier in the plane's modifier |
| 522 | 522 | * list is allowed with any of the plane's formats. |
| @@ -73,10 +73,21 @@ struct drm_privacy_screen { · 72 unmodified lines | ||
| 73 | 73 | * for more info. |
| 74 | 74 | */ |
| 75 | 75 | enum drm_privacy_screen_status hw_state; |
| 76 | + /** | |
| 77 | + * @drvdata: Private data owned by the privacy screen provider | |
| 78 | + */ | |
| 79 | + void *drvdata; | |
| 76 | 80 | }; |
| 77 | 81 | |
| 82 | +static inline | |
| 83 | +void *drm_privacy_screen_get_drvdata(struct drm_privacy_screen *priv) | |
| 84 | +{ | |
| 85 | + return priv->drvdata; | |
| 86 | +} | |
| 87 | + | |
| 78 | 88 | struct drm_privacy_screen *drm_privacy_screen_register( |
| 79 | − struct device *parent, const struct drm_privacy_screen_ops *ops); | |
| 89 | + struct device *parent, const struct drm_privacy_screen_ops *ops, | |
| 90 | + void *data); | |
| 80 | 91 | void drm_privacy_screen_unregister(struct drm_privacy_screen *priv); |
| 81 | 92 | |
| 82 | 93 | void drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen *priv); |
| @@ -105,11 +105,11 @@ struct ttm_resource_manager_func { · 104 unmodified lines | ||
| 105 | 105 | * @use_type: The memory type is enabled. |
| 106 | 106 | * @use_tt: If a TT object should be used for the backing store. |
| 107 | 107 | * @size: Size of the managed region. |
| 108 | + * @bdev: ttm device this manager belongs to | |
| 108 | 109 | * @func: structure pointer implementing the range manager. See above |
| 109 | 110 | * @move_lock: lock for move fence |
| 110 | − * static information. bdev::driver::io_mem_free is never used. | |
| 111 | − * @lru: The lru list for this memory type. | |
| 112 | 111 | * @move: The fence of the last pipelined move operation. |
| 112 | + * @lru: The lru list for this memory type. | |
| 113 | 113 | * |
| 114 | 114 | * This structure is used to identify and manage memory types for a device. |
| 115 | 115 | */ |
| @@ -119,20 +119,21 @@ struct ttm_resource_manager { · 3 unmodified lines | ||
| 119 | 119 | */ |
| 120 | 120 | bool use_type; |
| 121 | 121 | bool use_tt; |
| 122 | + struct ttm_device *bdev; | |
| 122 | 123 | uint64_t size; |
| 123 | 124 | const struct ttm_resource_manager_func *func; |
| 124 | 125 | spinlock_t move_lock; |
| 125 | 126 | |
| 126 | 127 | /* |
| 127 | − * Protected by the global->lru_lock. | |
| 128 | + * Protected by @move_lock. | |
| 128 | 129 | */ |
| 129 | − | |
| 130 | − struct list_head lru[TTM_MAX_BO_PRIORITY]; | |
| 130 | + struct dma_fence *move; | |
| 131 | 131 | |
| 132 | 132 | /* |
| 133 | − * Protected by @move_lock. | |
| 133 | + * Protected by the global->lru_lock. | |
| 134 | 134 | */ |
| 135 | − struct dma_fence *move; | |
| 135 | + | |
| 136 | + struct list_head lru[TTM_MAX_BO_PRIORITY]; | |
| 136 | 137 | }; |
| 137 | 138 | |
| 138 | 139 | /** |
| @@ -160,6 +161,7 @@ struct ttm_bus_placement { · 21 unmodified lines | ||
| 160 | 161 | * @mem_type: Resource type of the allocation. |
| 161 | 162 | * @placement: Placement flags. |
| 162 | 163 | * @bus: Placement on io bus accessible to the CPU |
| 164 | + * @bo: weak reference to the BO, protected by ttm_device::lru_lock | |
| 163 | 165 | * |
| 164 | 166 | * Structure indicating the placement and space resources used by a |
| 165 | 167 | * buffer object. |
| @@ -170,6 +172,7 @@ struct ttm_resource { · 4 unmodified lines | ||
| 170 | 172 | uint32_t mem_type; |
| 171 | 173 | uint32_t placement; |
| 172 | 174 | struct ttm_bus_placement bus; |
| 175 | + struct ttm_buffer_object *bo; | |
| 173 | 176 | }; |
| 174 | 177 | |
| 175 | 178 | /** |
| @@ -261,14 +264,20 @@ ttm_resource_manager_cleanup(struct ttm_resource_manager *man) · 85 unmodified lines | ||
| 261 | 264 | void ttm_resource_init(struct ttm_buffer_object *bo, |
| 262 | 265 | const struct ttm_place *place, |
| 263 | 266 | struct ttm_resource *res); |
| 267 | +void ttm_resource_fini(struct ttm_resource_manager *man, | |
| 268 | + struct ttm_resource *res); | |
| 269 | + | |
| 264 | 270 | int ttm_resource_alloc(struct ttm_buffer_object *bo, |
| 265 | 271 | const struct ttm_place *place, |
| 266 | 272 | struct ttm_resource **res); |
| 267 | 273 | void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res); |
| 268 | 274 | bool ttm_resource_compat(struct ttm_resource *res, |
| 269 | 275 | struct ttm_placement *placement); |
| 276 | +void ttm_resource_set_bo(struct ttm_resource *res, | |
| 277 | + struct ttm_buffer_object *bo); | |
| 270 | 278 | |
| 271 | 279 | void ttm_resource_manager_init(struct ttm_resource_manager *man, |
| 280 | + struct ttm_device *bdev, | |
| 272 | 281 | unsigned long p_size); |
| 273 | 282 | |
| 274 | 283 | int ttm_resource_manager_evict_all(struct ttm_device *bdev, |
| @@ -52,13 +52,13 @@ · 51 unmodified lines | ||
| 52 | 52 | * |
| 53 | 53 | * struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(0xdeadbeaf); |
| 54 | 54 | * |
| 55 | − * dma_buf_map_set_vaddr(&map. 0xdeadbeaf); | |
| 55 | + * dma_buf_map_set_vaddr(&map, 0xdeadbeaf); | |
| 56 | 56 | * |
| 57 | 57 | * To set an address in I/O memory, use dma_buf_map_set_vaddr_iomem(). |
| 58 | 58 | * |
| 59 | 59 | * .. code-block:: c |
| 60 | 60 | * |
| 61 | − * dma_buf_map_set_vaddr_iomem(&map. 0xdeadbeaf); | |
| 61 | + * dma_buf_map_set_vaddr_iomem(&map, 0xdeadbeaf); | |
| 62 | 62 | * |
| 63 | 63 | * Instances of struct dma_buf_map do not have to be cleaned up, but |
| 64 | 64 | * can be cleared to NULL with dma_buf_map_clear(). Cleared mappings |
| @@ -458,8 +458,8 @@ void dma_resv_fini(struct dma_resv *obj); · 457 unmodified lines | ||
| 458 | 458 | int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences); |
| 459 | 459 | void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence); |
| 460 | 460 | void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence); |
| 461 | −int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl, | |
| 462 | − unsigned *pshared_count, struct dma_fence ***pshared); | |
| 461 | +int dma_resv_get_fences(struct dma_resv *obj, bool write, | |
| 462 | + unsigned int *num_fences, struct dma_fence ***fences); | |
| 463 | 463 | int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src); |
| 464 | 464 | long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr, |
| 465 | 465 | unsigned long timeout); |
| @@ -502,6 +502,7 @@ struct fb_info { · 501 unmodified lines | ||
| 502 | 502 | } *apertures; |
| 503 | 503 | |
| 504 | 504 | bool skip_vt_switch; /* no VT switch on suspend/resume required */ |
| 505 | + bool forced_out; /* set when being removed by another driver */ | |
| 505 | 506 | }; |
| 506 | 507 | |
| 507 | 508 | static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { |
| @@ -230,7 +230,7 @@ extern void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map * · 229 unmodified lines | ||
| 230 | 230 | do { \ |
| 231 | 231 | typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \ |
| 232 | 232 | _down_write_nest_lock(sem, &(nest_lock)->dep_map); \ |
| 233 | −} while (0); | |
| 233 | +} while (0) | |
| 234 | 234 | |
| 235 | 235 | /* |
| 236 | 236 | * Take/release a lock when not the owner will release it. |
| @@ -91,6 +91,7 @@ enum rpi_firmware_property_tag { · 90 unmodified lines | ||
| 91 | 91 | RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049, |
| 92 | 92 | RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050, |
| 93 | 93 | RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058, |
| 94 | + RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 0x00030066, | |
| 94 | 95 | |
| 95 | 96 | /* Dispmanx TAGS */ |
| 96 | 97 | RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, |
| @@ -84,14 +84,14 @@ struct drm_panfrost_wait_bo { · 83 unmodified lines | ||
| 84 | 84 | __s64 timeout_ns; /* absolute */ |
| 85 | 85 | }; |
| 86 | 86 | |
| 87 | +/* Valid flags to pass to drm_panfrost_create_bo */ | |
| 87 | 88 | #define PANFROST_BO_NOEXEC 1 |
| 88 | 89 | #define PANFROST_BO_HEAP 2 |
| 89 | 90 | |
| 90 | 91 | /** |
| 91 | 92 | * struct drm_panfrost_create_bo - ioctl argument for creating Panfrost BOs. |
| 92 | 93 | * |
| 93 | − * There are currently no values for the flags argument, but it may be | |
| 94 | − * used in a future extension. | |
| 94 | + * The flags argument is a bit mask of PANFROST_BO_* flags. | |
| 95 | 95 | */ |
| 96 | 96 | struct drm_panfrost_create_bo { |
| 97 | 97 | __u32 size; |