drm-misc-next for 6.2: UAPI Changes: - Documentation for page-flip flags Cross-subsystem Changes: - dma-buf: Add unlocked variant of vmapping and attachment-mapping functions Core Changes: - atomic-helpers: CRTC primary plane test fixes - connector: TV API consistency improvements, cmdline parsing improvements - crtc-helpers: Introduce drm_crtc_helper_atomic_check() helper - edid: Fixes for HFVSDB parsing, - fourcc: Addition of the Vivante tiled modifier - makefile: Sort and reorganize the objects files - mode_config: Remove fb_base from drm_mode_config_funcs - sched: Add a module parameter to change the scheduling policy, refcounting fix for fences - tests: Sort the Kunit tests in the Makefile, improvements to the DP-MST tests - ttm: Remove unnecessary drm_mm_clean() call Driver Changes: - New driver: ofdrm - Move all drivers to a common dma-buf locking convention - bridge: - adv7533: Remove dynamic lane switching - it6505: Runtime PM support - ps8640: Handle AUX defer messages - tc358775: Drop soft-reset over I2C - ast: Atomic Gamma LUT Support, Convert to SHMEM, various improvements - lcdif: Support for YUV planes - mgag200: Fix PLL Setup on some revisions - udl: Modesetting improvements, hot-unplug support - vc4: Fix support for PAL-M Signed-off-by: Dave Airlie <airlied@redhat.com>
Unified · Split
| @@ -119,6 +119,12 @@ DMA Buffer ioctls · 118 unmodified lines | |||
| 119 | 119 | ||
| 120 | .. kernel-doc:: include/uapi/linux/dma-buf.h | 120 | .. kernel-doc:: include/uapi/linux/dma-buf.h |
| 121 | 121 | ||
| 122 | DMA-BUF locking convention | ||
| 123 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 124 | |||
| 125 | .. kernel-doc:: drivers/dma-buf/dma-buf.c | ||
| 126 | :doc: locking convention | ||
| 127 | |||
| 122 | Kernel Functions and Structures Reference | 128 | Kernel Functions and Structures Reference |
| 123 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 129 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 124 | 130 | ||
| @@ -6692,6 +6692,7 @@ L: dri-devel@lists.freedesktop.org · 6691 unmodified lines | |||
| 6692 | S: Maintained | 6692 | S: Maintained |
| 6693 | T: git git://anongit.freedesktop.org/drm/drm-misc | 6693 | T: git git://anongit.freedesktop.org/drm/drm-misc |
| 6694 | F: drivers/gpu/drm/drm_aperture.c | 6694 | F: drivers/gpu/drm/drm_aperture.c |
| 6695 | F: drivers/gpu/drm/tiny/ofdrm.c | ||
| 6695 | F: drivers/gpu/drm/tiny/simpledrm.c | 6696 | F: drivers/gpu/drm/tiny/simpledrm.c |
| 6696 | F: drivers/video/aperture.c | 6697 | F: drivers/video/aperture.c |
| 6697 | F: include/drm/drm_aperture.h | 6698 | F: include/drm/drm_aperture.h |
| @@ -657,7 +657,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) · 656 unmodified lines | |||
| 657 | 657 | ||
| 658 | dmabuf->file = file; | 658 | dmabuf->file = file; |
| 659 | 659 | ||
| 660 | mutex_init(&dmabuf->lock); | ||
| 661 | INIT_LIST_HEAD(&dmabuf->attachments); | 660 | INIT_LIST_HEAD(&dmabuf->attachments); |
| 662 | 661 | ||
| 663 | mutex_lock(&db_list.lock); | 662 | mutex_lock(&db_list.lock); |
| @@ -795,6 +794,70 @@ static struct sg_table * __map_dma_buf(struct dma_buf_attachment *attach, · 131 unmodified lines | |||
| 795 | return sg_table; | 794 | return sg_table; |
| 796 | } | 795 | } |
| 797 | 796 | ||
| 797 | /** | ||
| 798 | * DOC: locking convention | ||
| 799 | * | ||
| 800 | * In order to avoid deadlock situations between dma-buf exports and importers, | ||
| 801 | * all dma-buf API users must follow the common dma-buf locking convention. | ||
| 802 | * | ||
| 803 | * Convention for importers | ||
| 804 | * | ||
| 805 | * 1. Importers must hold the dma-buf reservation lock when calling these | ||
| 806 | * functions: | ||
| 807 | * | ||
| 808 | * - dma_buf_pin() | ||
| 809 | * - dma_buf_unpin() | ||
| 810 | * - dma_buf_map_attachment() | ||
| 811 | * - dma_buf_unmap_attachment() | ||
| 812 | * - dma_buf_vmap() | ||
| 813 | * - dma_buf_vunmap() | ||
| 814 | * | ||
| 815 | * 2. Importers must not hold the dma-buf reservation lock when calling these | ||
| 816 | * functions: | ||
| 817 | * | ||
| 818 | * - dma_buf_attach() | ||
| 819 | * - dma_buf_dynamic_attach() | ||
| 820 | * - dma_buf_detach() | ||
| 821 | * - dma_buf_export( | ||
| 822 | * - dma_buf_fd() | ||
| 823 | * - dma_buf_get() | ||
| 824 | * - dma_buf_put() | ||
| 825 | * - dma_buf_mmap() | ||
| 826 | * - dma_buf_begin_cpu_access() | ||
| 827 | * - dma_buf_end_cpu_access() | ||
| 828 | * - dma_buf_map_attachment_unlocked() | ||
| 829 | * - dma_buf_unmap_attachment_unlocked() | ||
| 830 | * - dma_buf_vmap_unlocked() | ||
| 831 | * - dma_buf_vunmap_unlocked() | ||
| 832 | * | ||
| 833 | * Convention for exporters | ||
| 834 | * | ||
| 835 | * 1. These &dma_buf_ops callbacks are invoked with unlocked dma-buf | ||
| 836 | * reservation and exporter can take the lock: | ||
| 837 | * | ||
| 838 | * - &dma_buf_ops.attach() | ||
| 839 | * - &dma_buf_ops.detach() | ||
| 840 | * - &dma_buf_ops.release() | ||
| 841 | * - &dma_buf_ops.begin_cpu_access() | ||
| 842 | * - &dma_buf_ops.end_cpu_access() | ||
| 843 | * | ||
| 844 | * 2. These &dma_buf_ops callbacks are invoked with locked dma-buf | ||
| 845 | * reservation and exporter can't take the lock: | ||
| 846 | * | ||
| 847 | * - &dma_buf_ops.pin() | ||
| 848 | * - &dma_buf_ops.unpin() | ||
| 849 | * - &dma_buf_ops.map_dma_buf() | ||
| 850 | * - &dma_buf_ops.unmap_dma_buf() | ||
| 851 | * - &dma_buf_ops.mmap() | ||
| 852 | * - &dma_buf_ops.vmap() | ||
| 853 | * - &dma_buf_ops.vunmap() | ||
| 854 | * | ||
| 855 | * 3. Exporters must hold the dma-buf reservation lock when calling these | ||
| 856 | * functions: | ||
| 857 | * | ||
| 858 | * - dma_buf_move_notify() | ||
| 859 | */ | ||
| 860 | |||
| 798 | /** | 861 | /** |
| 799 | * dma_buf_dynamic_attach - Add the device to dma_buf's attachments list | 862 | * dma_buf_dynamic_attach - Add the device to dma_buf's attachments list |
| 800 | * @dmabuf: [in] buffer to attach device to. | 863 | * @dmabuf: [in] buffer to attach device to. |
| @@ -859,8 +922,8 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, · 58 unmodified lines | |||
| 859 | dma_buf_is_dynamic(dmabuf)) { | 922 | dma_buf_is_dynamic(dmabuf)) { |
| 860 | struct sg_table *sgt; | 923 | struct sg_table *sgt; |
| 861 | 924 | ||
| 925 | dma_resv_lock(attach->dmabuf->resv, NULL); | ||
| 862 | if (dma_buf_is_dynamic(attach->dmabuf)) { | 926 | if (dma_buf_is_dynamic(attach->dmabuf)) { |
| 863 | dma_resv_lock(attach->dmabuf->resv, NULL); | ||
| 864 | ret = dmabuf->ops->pin(attach); | 927 | ret = dmabuf->ops->pin(attach); |
| 865 | if (ret) | 928 | if (ret) |
| 866 | goto err_unlock; | 929 | goto err_unlock; |
| @@ -873,8 +936,7 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, · 6 unmodified lines | |||
| 873 | ret = PTR_ERR(sgt); | 936 | ret = PTR_ERR(sgt); |
| 874 | goto err_unpin; | 937 | goto err_unpin; |
| 875 | } | 938 | } |
| 876 | if (dma_buf_is_dynamic(attach->dmabuf)) | 939 | dma_resv_unlock(attach->dmabuf->resv); |
| 877 | dma_resv_unlock(attach->dmabuf->resv); | ||
| 878 | attach->sgt = sgt; | 940 | attach->sgt = sgt; |
| 879 | attach->dir = DMA_BIDIRECTIONAL; | 941 | attach->dir = DMA_BIDIRECTIONAL; |
| 880 | } | 942 | } |
| @@ -890,8 +952,7 @@ err_unpin: · 9 unmodified lines | |||
| 890 | dmabuf->ops->unpin(attach); | 952 | dmabuf->ops->unpin(attach); |
| 891 | 953 | ||
| 892 | err_unlock: | 954 | err_unlock: |
| 893 | if (dma_buf_is_dynamic(attach->dmabuf)) | 955 | dma_resv_unlock(attach->dmabuf->resv); |
| 894 | dma_resv_unlock(attach->dmabuf->resv); | ||
| 895 | 956 | ||
| 896 | dma_buf_detach(dmabuf, attach); | 957 | dma_buf_detach(dmabuf, attach); |
| 897 | return ERR_PTR(ret); | 958 | return ERR_PTR(ret); |
| @@ -937,21 +998,19 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) · 39 unmodified lines | |||
| 937 | if (WARN_ON(!dmabuf || !attach)) | 998 | if (WARN_ON(!dmabuf || !attach)) |
| 938 | return; | 999 | return; |
| 939 | 1000 | ||
| 1001 | dma_resv_lock(attach->dmabuf->resv, NULL); | ||
| 1002 | |||
| 940 | if (attach->sgt) { | 1003 | if (attach->sgt) { |
| 941 | if (dma_buf_is_dynamic(attach->dmabuf)) | ||
| 942 | dma_resv_lock(attach->dmabuf->resv, NULL); | ||
| 943 | 1004 | ||
| 944 | __unmap_dma_buf(attach, attach->sgt, attach->dir); | 1005 | __unmap_dma_buf(attach, attach->sgt, attach->dir); |
| 945 | 1006 | ||
| 946 | if (dma_buf_is_dynamic(attach->dmabuf)) { | 1007 | if (dma_buf_is_dynamic(attach->dmabuf)) |
| 947 | dmabuf->ops->unpin(attach); | 1008 | dmabuf->ops->unpin(attach); |
| 948 | dma_resv_unlock(attach->dmabuf->resv); | ||
| 949 | } | ||
| 950 | } | 1009 | } |
| 951 | |||
| 952 | dma_resv_lock(dmabuf->resv, NULL); | ||
| 953 | list_del(&attach->node); | 1010 | list_del(&attach->node); |
| 1011 | |||
| 954 | dma_resv_unlock(dmabuf->resv); | 1012 | dma_resv_unlock(dmabuf->resv); |
| 1013 | |||
| 955 | if (dmabuf->ops->detach) | 1014 | if (dmabuf->ops->detach) |
| 956 | dmabuf->ops->detach(dmabuf, attach); | 1015 | dmabuf->ops->detach(dmabuf, attach); |
| 957 | 1016 | ||
| @@ -1042,8 +1101,7 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, · 84 unmodified lines | |||
| 1042 | if (WARN_ON(!attach || !attach->dmabuf)) | 1101 | if (WARN_ON(!attach || !attach->dmabuf)) |
| 1043 | return ERR_PTR(-EINVAL); | 1102 | return ERR_PTR(-EINVAL); |
| 1044 | 1103 | ||
| 1045 | if (dma_buf_attachment_is_dynamic(attach)) | 1104 | dma_resv_assert_held(attach->dmabuf->resv); |
| 1046 | dma_resv_assert_held(attach->dmabuf->resv); | ||
| 1047 | 1105 | ||
| 1048 | if (attach->sgt) { | 1106 | if (attach->sgt) { |
| 1049 | /* | 1107 | /* |
| @@ -1058,7 +1116,6 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, · 8 unmodified lines | |||
| 1058 | } | 1116 | } |
| 1059 | 1117 | ||
| 1060 | if (dma_buf_is_dynamic(attach->dmabuf)) { | 1118 | if (dma_buf_is_dynamic(attach->dmabuf)) { |
| 1061 | dma_resv_assert_held(attach->dmabuf->resv); | ||
| 1062 | if (!IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) { | 1119 | if (!IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) { |
| 1063 | r = attach->dmabuf->ops->pin(attach); | 1120 | r = attach->dmabuf->ops->pin(attach); |
| 1064 | if (r) | 1121 | if (r) |
| @@ -1100,6 +1157,34 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, · 35 unmodified lines | |||
| 1100 | } | 1157 | } |
| 1101 | EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment, DMA_BUF); | 1158 | EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment, DMA_BUF); |
| 1102 | 1159 | ||
| 1160 | /** | ||
| 1161 | * dma_buf_map_attachment_unlocked - Returns the scatterlist table of the attachment; | ||
| 1162 | * mapped into _device_ address space. Is a wrapper for map_dma_buf() of the | ||
| 1163 | * dma_buf_ops. | ||
| 1164 | * @attach: [in] attachment whose scatterlist is to be returned | ||
| 1165 | * @direction: [in] direction of DMA transfer | ||
| 1166 | * | ||
| 1167 | * Unlocked variant of dma_buf_map_attachment(). | ||
| 1168 | */ | ||
| 1169 | struct sg_table * | ||
| 1170 | dma_buf_map_attachment_unlocked(struct dma_buf_attachment *attach, | ||
| 1171 | enum dma_data_direction direction) | ||
| 1172 | { | ||
| 1173 | struct sg_table *sg_table; | ||
| 1174 | |||
| 1175 | might_sleep(); | ||
| 1176 | |||
| 1177 | if (WARN_ON(!attach || !attach->dmabuf)) | ||
| 1178 | return ERR_PTR(-EINVAL); | ||
| 1179 | |||
| 1180 | dma_resv_lock(attach->dmabuf->resv, NULL); | ||
| 1181 | sg_table = dma_buf_map_attachment(attach, direction); | ||
| 1182 | dma_resv_unlock(attach->dmabuf->resv); | ||
| 1183 | |||
| 1184 | return sg_table; | ||
| 1185 | } | ||
| 1186 | EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment_unlocked, DMA_BUF); | ||
| 1187 | |||
| 1103 | /** | 1188 | /** |
| 1104 | * dma_buf_unmap_attachment - unmaps and decreases usecount of the buffer;might | 1189 | * dma_buf_unmap_attachment - unmaps and decreases usecount of the buffer;might |
| 1105 | * deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of | 1190 | * deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of |
| @@ -1119,15 +1204,11 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, · 13 unmodified lines | |||
| 1119 | if (WARN_ON(!attach || !attach->dmabuf || !sg_table)) | 1204 | if (WARN_ON(!attach || !attach->dmabuf || !sg_table)) |
| 1120 | return; | 1205 | return; |
| 1121 | 1206 | ||
| 1122 | if (dma_buf_attachment_is_dynamic(attach)) | 1207 | dma_resv_assert_held(attach->dmabuf->resv); |
| 1123 | dma_resv_assert_held(attach->dmabuf->resv); | ||
| 1124 | 1208 | ||
| 1125 | if (attach->sgt == sg_table) | 1209 | if (attach->sgt == sg_table) |
| 1126 | return; | 1210 | return; |
| 1127 | 1211 | ||
| 1128 | if (dma_buf_is_dynamic(attach->dmabuf)) | ||
| 1129 | dma_resv_assert_held(attach->dmabuf->resv); | ||
| 1130 | |||
| 1131 | __unmap_dma_buf(attach, sg_table, direction); | 1212 | __unmap_dma_buf(attach, sg_table, direction); |
| 1132 | 1213 | ||
| 1133 | if (dma_buf_is_dynamic(attach->dmabuf) && | 1214 | if (dma_buf_is_dynamic(attach->dmabuf) && |
| @@ -1136,6 +1217,31 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, · 2 unmodified lines | |||
| 1136 | } | 1217 | } |
| 1137 | EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment, DMA_BUF); | 1218 | EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment, DMA_BUF); |
| 1138 | 1219 | ||
| 1220 | /** | ||
| 1221 | * dma_buf_unmap_attachment_unlocked - unmaps and decreases usecount of the buffer;might | ||
| 1222 | * deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of | ||
| 1223 | * dma_buf_ops. | ||
| 1224 | * @attach: [in] attachment to unmap buffer from | ||
| 1225 | * @sg_table: [in] scatterlist info of the buffer to unmap | ||
| 1226 | * @direction: [in] direction of DMA transfer | ||
| 1227 | * | ||
| 1228 | * Unlocked variant of dma_buf_unmap_attachment(). | ||
| 1229 | */ | ||
| 1230 | void dma_buf_unmap_attachment_unlocked(struct dma_buf_attachment *attach, | ||
| 1231 | struct sg_table *sg_table, | ||
| 1232 | enum dma_data_direction direction) | ||
| 1233 | { | ||
| 1234 | might_sleep(); | ||
| 1235 | |||
| 1236 | if (WARN_ON(!attach || !attach->dmabuf || !sg_table)) | ||
| 1237 | return; | ||
| 1238 | |||
| 1239 | dma_resv_lock(attach->dmabuf->resv, NULL); | ||
| 1240 | dma_buf_unmap_attachment(attach, sg_table, direction); | ||
| 1241 | dma_resv_unlock(attach->dmabuf->resv); | ||
| 1242 | } | ||
| 1243 | EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment_unlocked, DMA_BUF); | ||
| 1244 | |||
| 1139 | /** | 1245 | /** |
| 1140 | * dma_buf_move_notify - notify attachments that DMA-buf is moving | 1246 | * dma_buf_move_notify - notify attachments that DMA-buf is moving |
| 1141 | * | 1247 | * |
| @@ -1347,6 +1453,8 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_end_cpu_access, DMA_BUF); · 205 unmodified lines | |||
| 1347 | int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, | 1453 | int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, |
| 1348 | unsigned long pgoff) | 1454 | unsigned long pgoff) |
| 1349 | { | 1455 | { |
| 1456 | int ret; | ||
| 1457 | |||
| 1350 | if (WARN_ON(!dmabuf || !vma)) | 1458 | if (WARN_ON(!dmabuf || !vma)) |
| 1351 | return -EINVAL; | 1459 | return -EINVAL; |
| 1352 | 1460 | ||
| @@ -1367,7 +1475,11 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, · 14 unmodified lines | |||
| 1367 | vma_set_file(vma, dmabuf->file); | 1475 | vma_set_file(vma, dmabuf->file); |
| 1368 | vma->vm_pgoff = pgoff; | 1476 | vma->vm_pgoff = pgoff; |
| 1369 | 1477 | ||
| 1370 | return dmabuf->ops->mmap(dmabuf, vma); | 1478 | dma_resv_lock(dmabuf->resv, NULL); |
| 1479 | ret = dmabuf->ops->mmap(dmabuf, vma); | ||
| 1480 | dma_resv_unlock(dmabuf->resv); | ||
| 1481 | |||
| 1482 | return ret; | ||
| 1371 | } | 1483 | } |
| 1372 | EXPORT_SYMBOL_NS_GPL(dma_buf_mmap, DMA_BUF); | 1484 | EXPORT_SYMBOL_NS_GPL(dma_buf_mmap, DMA_BUF); |
| 1373 | 1485 | ||
| @@ -1390,41 +1502,67 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_mmap, DMA_BUF); · 16 unmodified lines | |||
| 1390 | int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map) | 1502 | int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map) |
| 1391 | { | 1503 | { |
| 1392 | struct iosys_map ptr; | 1504 | struct iosys_map ptr; |
| 1393 | int ret = 0; | 1505 | int ret; |
| 1394 | 1506 | ||
| 1395 | iosys_map_clear(map); | 1507 | iosys_map_clear(map); |
| 1396 | 1508 | ||
| 1397 | if (WARN_ON(!dmabuf)) | 1509 | if (WARN_ON(!dmabuf)) |
| 1398 | return -EINVAL; | 1510 | return -EINVAL; |
| 1399 | 1511 | ||
| 1512 | dma_resv_assert_held(dmabuf->resv); | ||
| 1513 | |||
| 1400 | if (!dmabuf->ops->vmap) | 1514 | if (!dmabuf->ops->vmap) |
| 1401 | return -EINVAL; | 1515 | return -EINVAL; |
| 1402 | 1516 | ||
| 1403 | mutex_lock(&dmabuf->lock); | ||
| 1404 | if (dmabuf->vmapping_counter) { | 1517 | if (dmabuf->vmapping_counter) { |
| 1405 | dmabuf->vmapping_counter++; | 1518 | dmabuf->vmapping_counter++; |
| 1406 | BUG_ON(iosys_map_is_null(&dmabuf->vmap_ptr)); | 1519 | BUG_ON(iosys_map_is_null(&dmabuf->vmap_ptr)); |
| 1407 | *map = dmabuf->vmap_ptr; | 1520 | *map = dmabuf->vmap_ptr; |
| 1408 | goto out_unlock; | 1521 | return 0; |
| 1409 | } | 1522 | } |
| 1410 | 1523 | ||
| 1411 | BUG_ON(iosys_map_is_set(&dmabuf->vmap_ptr)); | 1524 | BUG_ON(iosys_map_is_set(&dmabuf->vmap_ptr)); |
| 1412 | 1525 | ||
| 1413 | ret = dmabuf->ops->vmap(dmabuf, &ptr); | 1526 | ret = dmabuf->ops->vmap(dmabuf, &ptr); |
| 1414 | if (WARN_ON_ONCE(ret)) | 1527 | if (WARN_ON_ONCE(ret)) |
| 1415 | goto out_unlock; | 1528 | return ret; |
| 1416 | 1529 | ||
| 1417 | dmabuf->vmap_ptr = ptr; | 1530 | dmabuf->vmap_ptr = ptr; |
| 1418 | dmabuf->vmapping_counter = 1; | 1531 | dmabuf->vmapping_counter = 1; |
| 1419 | 1532 | ||
| 1420 | *map = dmabuf->vmap_ptr; | 1533 | *map = dmabuf->vmap_ptr; |
| 1421 | 1534 | ||
| 1422 | out_unlock: | 1535 | return 0; |
| 1423 | mutex_unlock(&dmabuf->lock); | ||
| 1424 | return ret; | ||
| 1425 | } | 1536 | } |
| 1426 | EXPORT_SYMBOL_NS_GPL(dma_buf_vmap, DMA_BUF); | 1537 | EXPORT_SYMBOL_NS_GPL(dma_buf_vmap, DMA_BUF); |
| 1427 | 1538 | ||
| 1539 | /** | ||
| 1540 | * dma_buf_vmap_unlocked - Create virtual mapping for the buffer object into kernel | ||
| 1541 | * address space. Same restrictions as for vmap and friends apply. | ||
| 1542 | * @dmabuf: [in] buffer to vmap | ||
| 1543 | * @map: [out] returns the vmap pointer | ||
| 1544 | * | ||
| 1545 | * Unlocked version of dma_buf_vmap() | ||
| 1546 | * | ||
| 1547 | * Returns 0 on success, or a negative errno code otherwise. | ||
| 1548 | */ | ||
| 1549 | int dma_buf_vmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map) | ||
| 1550 | { | ||
| 1551 | int ret; | ||
| 1552 | |||
| 1553 | iosys_map_clear(map); | ||
| 1554 | |||
| 1555 | if (WARN_ON(!dmabuf)) | ||
| 1556 | return -EINVAL; | ||
| 1557 | |||
| 1558 | dma_resv_lock(dmabuf->resv, NULL); | ||
| 1559 | ret = dma_buf_vmap(dmabuf, map); | ||
| 1560 | dma_resv_unlock(dmabuf->resv); | ||
| 1561 | |||
| 1562 | return ret; | ||
| 1563 | } | ||
| 1564 | EXPORT_SYMBOL_NS_GPL(dma_buf_vmap_unlocked, DMA_BUF); | ||
| 1565 | |||
| 1428 | /** | 1566 | /** |
| 1429 | * dma_buf_vunmap - Unmap a vmap obtained by dma_buf_vmap. | 1567 | * dma_buf_vunmap - Unmap a vmap obtained by dma_buf_vmap. |
| 1430 | * @dmabuf: [in] buffer to vunmap | 1568 | * @dmabuf: [in] buffer to vunmap |
| @@ -1435,20 +1573,36 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map) · 4 unmodified lines | |||
| 1435 | if (WARN_ON(!dmabuf)) | 1573 | if (WARN_ON(!dmabuf)) |
| 1436 | return; | 1574 | return; |
| 1437 | 1575 | ||
| 1576 | dma_resv_assert_held(dmabuf->resv); | ||
| 1577 | |||
| 1438 | BUG_ON(iosys_map_is_null(&dmabuf->vmap_ptr)); | 1578 | BUG_ON(iosys_map_is_null(&dmabuf->vmap_ptr)); |
| 1439 | BUG_ON(dmabuf->vmapping_counter == 0); | 1579 | BUG_ON(dmabuf->vmapping_counter == 0); |
| 1440 | BUG_ON(!iosys_map_is_equal(&dmabuf->vmap_ptr, map)); | 1580 | BUG_ON(!iosys_map_is_equal(&dmabuf->vmap_ptr, map)); |
| 1441 | 1581 | ||
| 1442 | mutex_lock(&dmabuf->lock); | ||
| 1443 | if (--dmabuf->vmapping_counter == 0) { | 1582 | if (--dmabuf->vmapping_counter == 0) { |
| 1444 | if (dmabuf->ops->vunmap) | 1583 | if (dmabuf->ops->vunmap) |
| 1445 | dmabuf->ops->vunmap(dmabuf, map); | 1584 | dmabuf->ops->vunmap(dmabuf, map); |
| 1446 | iosys_map_clear(&dmabuf->vmap_ptr); | 1585 | iosys_map_clear(&dmabuf->vmap_ptr); |
| 1447 | } | 1586 | } |
| 1448 | mutex_unlock(&dmabuf->lock); | ||
| 1449 | } | 1587 | } |
| 1450 | EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap, DMA_BUF); | 1588 | EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap, DMA_BUF); |
| 1451 | 1589 | ||
| 1590 | /** | ||
| 1591 | * dma_buf_vunmap_unlocked - Unmap a vmap obtained by dma_buf_vmap. | ||
| 1592 | * @dmabuf: [in] buffer to vunmap | ||
| 1593 | * @map: [in] vmap pointer to vunmap | ||
| 1594 | */ | ||
| 1595 | void dma_buf_vunmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map) | ||
| 1596 | { | ||
| 1597 | if (WARN_ON(!dmabuf)) | ||
| 1598 | return; | ||
| 1599 | |||
| 1600 | dma_resv_lock(dmabuf->resv, NULL); | ||
| 1601 | dma_buf_vunmap(dmabuf, map); | ||
| 1602 | dma_resv_unlock(dmabuf->resv); | ||
| 1603 | } | ||
| 1604 | EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap_unlocked, DMA_BUF); | ||
| 1605 | |||
| 1452 | #ifdef CONFIG_DEBUG_FS | 1606 | #ifdef CONFIG_DEBUG_FS |
| 1453 | static int dma_buf_debug_show(struct seq_file *s, void *unused) | 1607 | static int dma_buf_debug_show(struct seq_file *s, void *unused) |
| 1454 | { | 1608 | { |
| @@ -5,32 +5,71 @@ · 4 unmodified lines | |||
| 5 | 5 | ||
| 6 | CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE | 6 | CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE |
| 7 | 7 | ||
| 8 | drm-y := drm_aperture.o drm_auth.o drm_cache.o \ | 8 | drm-y := \ |
| 9 | drm_file.o drm_gem.o drm_ioctl.o \ | 9 | drm_aperture.o \ |
| 10 | drm_drv.o \ | 10 | drm_atomic.o \ |
| 11 | drm_sysfs.o drm_mm.o \ | 11 | drm_atomic_uapi.o \ |
| 12 | drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o drm_displayid.o \ | 12 | drm_auth.o \ |
| 13 | drm_trace_points.o drm_prime.o \ | 13 | drm_blend.o \ |
| 14 | drm_vma_manager.o \ | 14 | drm_bridge.o \ |
| 15 | drm_modeset_lock.o drm_atomic.o drm_bridge.o \ | 15 | drm_cache.o \ |
| 16 | drm_framebuffer.o drm_connector.o drm_blend.o \ | 16 | drm_client.o \ |
| 17 | drm_encoder.o drm_mode_object.o drm_property.o \ | 17 | drm_client_modeset.o \ |
| 18 | drm_plane.o drm_color_mgmt.o drm_print.o \ | 18 | drm_color_mgmt.o \ |
| 19 | drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ | 19 | drm_connector.o \ |
| 20 | drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \ | 20 | drm_crtc.o \ |
| 21 | drm_client_modeset.o drm_atomic_uapi.o \ | 21 | drm_displayid.o \ |
| 22 | drm_managed.o drm_vblank_work.o | 22 | drm_drv.o \ |
| 23 | drm-$(CONFIG_DRM_LEGACY) += drm_agpsupport.o drm_bufs.o drm_context.o drm_dma.o \ | 23 | drm_dumb_buffers.o \ |
| 24 | drm_hashtab.o drm_irq.o drm_legacy_misc.o drm_lock.o \ | 24 | drm_edid.o \ |
| 25 | drm_memory.o drm_scatter.o drm_vm.o | 25 | drm_encoder.o \ |
| 26 | drm_file.o \ | ||
| 27 | drm_fourcc.o \ | ||
| 28 | drm_framebuffer.o \ | ||
| 29 | drm_gem.o \ | ||
| 30 | drm_ioctl.o \ | ||
| 31 | drm_lease.o \ | ||
| 32 | drm_managed.o \ | ||
| 33 | drm_mm.o \ | ||
| 34 | drm_mode_config.o \ | ||
| 35 | drm_mode_object.o \ | ||
| 36 | drm_modes.o \ | ||
| 37 | drm_modeset_lock.o \ | ||
| 38 | drm_plane.o \ | ||
| 39 | drm_prime.o \ | ||
| 40 | drm_print.o \ | ||
| 41 | drm_property.o \ | ||
| 42 | drm_syncobj.o \ | ||
| 43 | drm_sysfs.o \ | ||
| 44 | drm_trace_points.o \ | ||
| 45 | drm_vblank.o \ | ||
| 46 | drm_vblank_work.o \ | ||
| 47 | drm_vma_manager.o \ | ||
| 48 | drm_writeback.o | ||
| 49 | drm-$(CONFIG_DRM_LEGACY) += \ | ||
| 50 | drm_agpsupport.o \ | ||
| 51 | drm_bufs.o \ | ||
| 52 | drm_context.o \ | ||
| 53 | drm_dma.o \ | ||
| 54 | drm_hashtab.o \ | ||
| 55 | drm_irq.o \ | ||
| 56 | drm_legacy_misc.o \ | ||
| 57 | drm_lock.o \ | ||
| 58 | drm_memory.o \ | ||
| 59 | drm_scatter.o \ | ||
| 60 | drm_vm.o | ||
| 26 | drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o | 61 | drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o |
| 27 | drm-$(CONFIG_COMPAT) += drm_ioc32.o | 62 | drm-$(CONFIG_COMPAT) += drm_ioc32.o |
| 28 | drm-$(CONFIG_DRM_PANEL) += drm_panel.o | 63 | drm-$(CONFIG_DRM_PANEL) += drm_panel.o |
| 29 | drm-$(CONFIG_OF) += drm_of.o | 64 | drm-$(CONFIG_OF) += drm_of.o |
| 30 | drm-$(CONFIG_PCI) += drm_pci.o | 65 | drm-$(CONFIG_PCI) += drm_pci.o |
| 31 | drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o | 66 | drm-$(CONFIG_DEBUG_FS) += \ |
| 67 | drm_debugfs.o \ | ||
| 68 | drm_debugfs_crc.o | ||
| 32 | drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o | 69 | drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o |
| 33 | drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o drm_privacy_screen_x86.o | 70 | drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \ |
| 71 | drm_privacy_screen.o \ | ||
| 72 | drm_privacy_screen_x86.o | ||
| 34 | obj-$(CONFIG_DRM) += drm.o | 73 | obj-$(CONFIG_DRM) += drm.o |
| 35 | 74 | ||
| 36 | obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o | 75 | obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o |
| @@ -59,16 +98,24 @@ obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o · 22 unmodified lines | |||
| 59 | # Modesetting helpers | 98 | # Modesetting helpers |
| 60 | # | 99 | # |
| 61 | 100 | ||
| 62 | drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \ | 101 | drm_kms_helper-y := \ |
| 63 | drm_encoder_slave.o drm_flip_work.o \ | 102 | drm_atomic_helper.o \ |
| 64 | drm_probe_helper.o \ | 103 | drm_atomic_state_helper.o \ |
| 65 | drm_plane_helper.o drm_atomic_helper.o \ | 104 | drm_bridge_connector.o \ |
| 66 | drm_kms_helper_common.o \ | 105 | drm_crtc_helper.o \ |
| 67 | drm_simple_kms_helper.o drm_modeset_helper.o \ | 106 | drm_damage_helper.o \ |
| 68 | drm_gem_atomic_helper.o \ | 107 | drm_encoder_slave.o \ |
| 69 | drm_gem_framebuffer_helper.o \ | 108 | drm_flip_work.o \ |
| 70 | drm_atomic_state_helper.o drm_damage_helper.o \ | 109 | drm_format_helper.o \ |
| 71 | drm_format_helper.o drm_self_refresh_helper.o drm_rect.o | 110 | drm_gem_atomic_helper.o \ |
| 111 | drm_gem_framebuffer_helper.o \ | ||
| 112 | drm_kms_helper_common.o \ | ||
| 113 | drm_modeset_helper.o \ | ||
| 114 | drm_plane_helper.o \ | ||
| 115 | drm_probe_helper.o \ | ||
| 116 | drm_rect.o \ | ||
| 117 | drm_self_refresh_helper.o \ | ||
| 118 | drm_simple_kms_helper.o | ||
| 72 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o | 119 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o |
| 73 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o | 120 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o |
| 74 | obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o | 121 | obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o |
| @@ -498,8 +498,6 @@ static int amdgpu_vkms_sw_init(void *handle) · 497 unmodified lines | |||
| 498 | adev_to_drm(adev)->mode_config.preferred_depth = 24; | 498 | adev_to_drm(adev)->mode_config.preferred_depth = 24; |
| 499 | adev_to_drm(adev)->mode_config.prefer_shadow = 1; | 499 | adev_to_drm(adev)->mode_config.prefer_shadow = 1; |
| 500 | 500 | ||
| 501 | adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; | ||
| 502 | |||
| 503 | r = amdgpu_display_modeset_create_props(adev); | 501 | r = amdgpu_display_modeset_create_props(adev); |
| 504 | if (r) | 502 | if (r) |
| 505 | return r; | 503 | return r; |
| @@ -2800,8 +2800,6 @@ static int dce_v10_0_sw_init(void *handle) · 2799 unmodified lines | |||
| 2800 | 2800 | ||
| 2801 | adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; | 2801 | adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; |
| 2802 | 2802 | ||
| 2803 | adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; | ||
| 2804 | |||
| 2805 | r = amdgpu_display_modeset_create_props(adev); | 2803 | r = amdgpu_display_modeset_create_props(adev); |
| 2806 | if (r) | 2804 | if (r) |
| 2807 | return r; | 2805 | return r; |
| @@ -2918,8 +2918,6 @@ static int dce_v11_0_sw_init(void *handle) · 2917 unmodified lines | |||
| 2918 | 2918 | ||
| 2919 | adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; | 2919 | adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; |
| 2920 | 2920 | ||
| 2921 | adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; | ||
| 2922 | |||
| 2923 | r = amdgpu_display_modeset_create_props(adev); | 2921 | r = amdgpu_display_modeset_create_props(adev); |
| 2924 | if (r) | 2922 | if (r) |
| 2925 | return r; | 2923 | return r; |
| @@ -2675,7 +2675,6 @@ static int dce_v6_0_sw_init(void *handle) · 2674 unmodified lines | |||
| 2675 | adev_to_drm(adev)->mode_config.preferred_depth = 24; | 2675 | adev_to_drm(adev)->mode_config.preferred_depth = 24; |
| 2676 | adev_to_drm(adev)->mode_config.prefer_shadow = 1; | 2676 | adev_to_drm(adev)->mode_config.prefer_shadow = 1; |
| 2677 | adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; | 2677 | adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; |
| 2678 | adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; | ||
| 2679 | 2678 | ||
| 2680 | r = amdgpu_display_modeset_create_props(adev); | 2679 | r = amdgpu_display_modeset_create_props(adev); |
| 2681 | if (r) | 2680 | if (r) |
| @@ -2701,8 +2701,6 @@ static int dce_v8_0_sw_init(void *handle) · 2700 unmodified lines | |||
| 2701 | 2701 | ||
| 2702 | adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; | 2702 | adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; |
| 2703 | 2703 | ||
| 2704 | adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; | ||
| 2705 | |||
| 2706 | r = amdgpu_display_modeset_create_props(adev); | 2704 | r = amdgpu_display_modeset_create_props(adev); |
| 2707 | if (r) | 2705 | if (r) |
| 2708 | return r; | 2706 | return r; |
| @@ -3816,8 +3816,6 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) · 3815 unmodified lines | |||
| 3816 | /* indicates support for immediate flip */ | 3816 | /* indicates support for immediate flip */ |
| 3817 | adev_to_drm(adev)->mode_config.async_page_flip = true; | 3817 | adev_to_drm(adev)->mode_config.async_page_flip = true; |
| 3818 | 3818 | ||
| 3819 | adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; | ||
| 3820 | |||
| 3821 | state = kzalloc(sizeof(*state), GFP_KERNEL); | 3819 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
| 3822 | if (!state) | 3820 | if (!state) |
| 3823 | return -ENOMEM; | 3821 | return -ENOMEM; |
| @@ -66,8 +66,8 @@ void armada_gem_free_object(struct drm_gem_object *obj) · 65 unmodified lines | |||
| 66 | if (dobj->obj.import_attach) { | 66 | if (dobj->obj.import_attach) { |
| 67 | /* We only ever display imported data */ | 67 | /* We only ever display imported data */ |
| 68 | if (dobj->sgt) | 68 | if (dobj->sgt) |
| 69 | dma_buf_unmap_attachment(dobj->obj.import_attach, | 69 | dma_buf_unmap_attachment_unlocked(dobj->obj.import_attach, |
| 70 | dobj->sgt, DMA_TO_DEVICE); | 70 | dobj->sgt, DMA_TO_DEVICE); |
| 71 | drm_prime_gem_destroy(&dobj->obj, NULL); | 71 | drm_prime_gem_destroy(&dobj->obj, NULL); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| @@ -539,8 +539,8 @@ int armada_gem_map_import(struct armada_gem_object *dobj) · 465 unmodified lines | |||
| 539 | { | 539 | { |
| 540 | int ret; | 540 | int ret; |
| 541 | 541 | ||
| 542 | dobj->sgt = dma_buf_map_attachment(dobj->obj.import_attach, | 542 | dobj->sgt = dma_buf_map_attachment_unlocked(dobj->obj.import_attach, |
| 543 | DMA_TO_DEVICE); | 543 | DMA_TO_DEVICE); |
| 544 | if (IS_ERR(dobj->sgt)) { | 544 | if (IS_ERR(dobj->sgt)) { |
| 545 | ret = PTR_ERR(dobj->sgt); | 545 | ret = PTR_ERR(dobj->sgt); |
| 546 | dobj->sgt = NULL; | 546 | dobj->sgt = NULL; |
| @@ -2,10 +2,8 @@ · 1 unmodified line | |||
| 2 | config DRM_AST | 2 | config DRM_AST |
| 3 | tristate "AST server chips" | 3 | tristate "AST server chips" |
| 4 | depends on DRM && PCI && MMU | 4 | depends on DRM && PCI && MMU |
| 5 | select DRM_GEM_SHMEM_HELPER | ||
| 5 | select DRM_KMS_HELPER | 6 | select DRM_KMS_HELPER |
| 6 | select DRM_VRAM_HELPER | ||
| 7 | select DRM_TTM | ||
| 8 | select DRM_TTM_HELPER | ||
| 9 | help | 7 | help |
| 10 | Say yes for experimental AST GPU driver. Do not enable | 8 | Say yes for experimental AST GPU driver. Do not enable |
| 11 | this driver without having a working -modesetting, | 9 | this driver without having a working -modesetting, |
| @@ -33,7 +33,7 @@ · 32 unmodified lines | |||
| 33 | #include <drm/drm_atomic_helper.h> | 33 | #include <drm/drm_atomic_helper.h> |
| 34 | #include <drm/drm_crtc_helper.h> | 34 | #include <drm/drm_crtc_helper.h> |
| 35 | #include <drm/drm_drv.h> | 35 | #include <drm/drm_drv.h> |
| 36 | #include <drm/drm_gem_vram_helper.h> | 36 | #include <drm/drm_gem_shmem_helper.h> |
| 37 | #include <drm/drm_module.h> | 37 | #include <drm/drm_module.h> |
| 38 | #include <drm/drm_probe_helper.h> | 38 | #include <drm/drm_probe_helper.h> |
| 39 | 39 | ||
| @@ -63,7 +63,7 @@ static const struct drm_driver ast_driver = { · 23 unmodified lines | |||
| 63 | .minor = DRIVER_MINOR, | 63 | .minor = DRIVER_MINOR, |
| 64 | .patchlevel = DRIVER_PATCHLEVEL, | 64 | .patchlevel = DRIVER_PATCHLEVEL, |
| 65 | 65 | ||
| 66 | DRM_GEM_VRAM_DRIVER | 66 | DRM_GEM_SHMEM_DRIVER_OPS |
| 67 | }; | 67 | }; |
| 68 | 68 | ||
| 69 | /* | 69 | /* |
| @@ -87,7 +87,7 @@ enum ast_tx_chip { · 86 unmodified lines | |||
| 87 | #define AST_DRAM_8Gx16 8 | 87 | #define AST_DRAM_8Gx16 8 |
| 88 | 88 | ||
| 89 | /* | 89 | /* |
| 90 | * Cursor plane | 90 | * Hardware cursor |
| 91 | */ | 91 | */ |
| 92 | 92 | ||
| 93 | #define AST_MAX_HWC_WIDTH 64 | 93 | #define AST_MAX_HWC_WIDTH 64 |
| @@ -96,8 +96,6 @@ enum ast_tx_chip { · 2 unmodified lines | |||
| 96 | #define AST_HWC_SIZE (AST_MAX_HWC_WIDTH * AST_MAX_HWC_HEIGHT * 2) | 96 | #define AST_HWC_SIZE (AST_MAX_HWC_WIDTH * AST_MAX_HWC_HEIGHT * 2) |
| 97 | #define AST_HWC_SIGNATURE_SIZE 32 | 97 | #define AST_HWC_SIGNATURE_SIZE 32 |
| 98 | 98 | ||
| 99 | #define AST_DEFAULT_HWC_NUM 2 | ||
| 100 | |||
| 101 | /* define for signature structure */ | 99 | /* define for signature structure */ |
| 102 | #define AST_HWC_SIGNATURE_CHECKSUM 0x00 | 100 | #define AST_HWC_SIGNATURE_CHECKSUM 0x00 |
| 103 | #define AST_HWC_SIGNATURE_SizeX 0x04 | 101 | #define AST_HWC_SIGNATURE_SizeX 0x04 |
| @@ -107,22 +105,21 @@ enum ast_tx_chip { · 3 unmodified lines | |||
| 107 | #define AST_HWC_SIGNATURE_HOTSPOTX 0x14 | 105 | #define AST_HWC_SIGNATURE_HOTSPOTX 0x14 |
| 108 | #define AST_HWC_SIGNATURE_HOTSPOTY 0x18 | 106 | #define AST_HWC_SIGNATURE_HOTSPOTY 0x18 |
| 109 | 107 | ||
| 110 | struct ast_cursor_plane { | 108 | /* |
| 111 | struct drm_plane base; | 109 | * Planes |
| 110 | */ | ||
| 112 | 111 | ||
| 113 | struct { | 112 | struct ast_plane { |
| 114 | struct drm_gem_vram_object *gbo; | 113 | struct drm_plane base; |
| 115 | struct iosys_map map; | ||
| 116 | u64 off; | ||
| 117 | } hwc[AST_DEFAULT_HWC_NUM]; | ||
| 118 | 114 | ||
| 119 | unsigned int next_hwc_index; | 115 | void __iomem *vaddr; |
| 116 | u64 offset; | ||
| 117 | unsigned long size; | ||
| 120 | }; | 118 | }; |
| 121 | 119 | ||
| 122 | static inline struct ast_cursor_plane * | 120 | static inline struct ast_plane *to_ast_plane(struct drm_plane *plane) |
| 123 | to_ast_cursor_plane(struct drm_plane *plane) | ||
| 124 | { | 121 | { |
| 125 | return container_of(plane, struct ast_cursor_plane, base); | 122 | return container_of(plane, struct ast_plane, base); |
| 126 | } | 123 | } |
| 127 | 124 | ||
| 128 | /* | 125 | /* |
| @@ -175,8 +172,13 @@ struct ast_private { · 46 unmodified lines | |||
| 175 | uint32_t dram_type; | 172 | uint32_t dram_type; |
| 176 | uint32_t mclk; | 173 | uint32_t mclk; |
| 177 | 174 | ||
| 178 | struct drm_plane primary_plane; | 175 | void __iomem *vram; |
| 179 | struct ast_cursor_plane cursor_plane; | 176 | unsigned long vram_base; |
| 177 | unsigned long vram_size; | ||
| 178 | unsigned long vram_fb_available; | ||
| 179 | |||
| 180 | struct ast_plane primary_plane; | ||
| 181 | struct ast_plane cursor_plane; | ||
| 180 | struct drm_crtc crtc; | 182 | struct drm_crtc crtc; |
| 181 | struct { | 183 | struct { |
| 182 | struct { | 184 | struct { |
| @@ -32,7 +32,6 @@ · 31 unmodified lines | |||
| 32 | #include <drm/drm_crtc_helper.h> | 32 | #include <drm/drm_crtc_helper.h> |
| 33 | #include <drm/drm_drv.h> | 33 | #include <drm/drm_drv.h> |
| 34 | #include <drm/drm_gem.h> | 34 | #include <drm/drm_gem.h> |
| 35 | #include <drm/drm_gem_vram_helper.h> | ||
| 36 | #include <drm/drm_managed.h> | 35 | #include <drm/drm_managed.h> |
| 37 | 36 | ||
| 38 | #include "ast_drv.h" | 37 | #include "ast_drv.h" |
| @@ -461,8 +460,8 @@ struct ast_private *ast_device_create(const struct drm_driver *drv, · 422 unmodified lines | |||
| 461 | 460 | ||
| 462 | /* map reserved buffer */ | 461 | /* map reserved buffer */ |
| 463 | ast->dp501_fw_buf = NULL; | 462 | ast->dp501_fw_buf = NULL; |
| 464 | if (dev->vram_mm->vram_size < pci_resource_len(pdev, 0)) { | 463 | if (ast->vram_size < pci_resource_len(pdev, 0)) { |
| 465 | ast->dp501_fw_buf = pci_iomap_range(pdev, 0, dev->vram_mm->vram_size, 0); | 464 | ast->dp501_fw_buf = pci_iomap_range(pdev, 0, ast->vram_size, 0); |
| 466 | if (!ast->dp501_fw_buf) | 465 | if (!ast->dp501_fw_buf) |
| 467 | drm_info(dev, "failed to map reserved buffer!\n"); | 466 | drm_info(dev, "failed to map reserved buffer!\n"); |
| 468 | } | 467 | } |
| @@ -28,7 +28,6 @@ · 27 unmodified lines | |||
| 28 | 28 | ||
| 29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
| 30 | 30 | ||
| 31 | #include <drm/drm_gem_vram_helper.h> | ||
| 32 | #include <drm/drm_managed.h> | 31 | #include <drm/drm_managed.h> |
| 33 | #include <drm/drm_print.h> | 32 | #include <drm/drm_print.h> |
| 34 | 33 | ||
| @@ -80,7 +79,6 @@ int ast_mm_init(struct ast_private *ast) · 45 unmodified lines | |||
| 80 | struct pci_dev *pdev = to_pci_dev(dev->dev); | 79 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
| 81 | resource_size_t base, size; | 80 | resource_size_t base, size; |
| 82 | u32 vram_size; | 81 | u32 vram_size; |
| 83 | int ret; | ||
| 84 | 82 | ||
| 85 | base = pci_resource_start(pdev, 0); | 83 | base = pci_resource_start(pdev, 0); |
| 86 | size = pci_resource_len(pdev, 0); | 84 | size = pci_resource_len(pdev, 0); |
| @@ -91,11 +89,13 @@ int ast_mm_init(struct ast_private *ast) · 4 unmodified lines | |||
| 91 | 89 | ||
| 92 | vram_size = ast_get_vram_size(ast); | 90 | vram_size = ast_get_vram_size(ast); |
| 93 | 91 | ||
| 94 | ret = drmm_vram_helper_init(dev, base, vram_size); | 92 | ast->vram = devm_ioremap_wc(dev->dev, base, vram_size); |
| 95 | if (ret) { | 93 | if (!ast->vram) |
| 96 | drm_err(dev, "Error initializing VRAM MM; %d\n", ret); | 94 | return -ENOMEM; |
| 97 | return ret; | 95 | |
| 98 | } | 96 | ast->vram_base = base; |
| 97 | ast->vram_size = vram_size; | ||
| 98 | ast->vram_fb_available = vram_size; | ||
| 99 | 99 | ||
| 100 | return 0; | 100 | return 0; |
| 101 | } | 101 | } |
| @@ -36,11 +36,13 @@ · 35 unmodified lines | |||
| 36 | #include <drm/drm_atomic_state_helper.h> | 36 | #include <drm/drm_atomic_state_helper.h> |
| 37 | #include <drm/drm_crtc.h> | 37 | #include <drm/drm_crtc.h> |
| 38 | #include <drm/drm_crtc_helper.h> | 38 | #include <drm/drm_crtc_helper.h> |
| 39 | #include <drm/drm_damage_helper.h> | ||
| 39 | #include <drm/drm_edid.h> | 40 | #include <drm/drm_edid.h> |
| 41 | #include <drm/drm_format_helper.h> | ||
| 40 | #include <drm/drm_fourcc.h> | 42 | #include <drm/drm_fourcc.h> |
| 41 | #include <drm/drm_gem_atomic_helper.h> | 43 | #include <drm/drm_gem_atomic_helper.h> |
| 42 | #include <drm/drm_gem_framebuffer_helper.h> | 44 | #include <drm/drm_gem_framebuffer_helper.h> |
| 43 | #include <drm/drm_gem_vram_helper.h> | 45 | #include <drm/drm_gem_shmem_helper.h> |
| 44 | #include <drm/drm_managed.h> | 46 | #include <drm/drm_managed.h> |
| 45 | #include <drm/drm_probe_helper.h> | 47 | #include <drm/drm_probe_helper.h> |
| 46 | #include <drm/drm_simple_kms_helper.h> | 48 | #include <drm/drm_simple_kms_helper.h> |
| @@ -48,6 +50,8 @@ · 1 unmodified line | |||
| 48 | #include "ast_drv.h" | 50 | #include "ast_drv.h" |
| 49 | #include "ast_tables.h" | 51 | #include "ast_tables.h" |
| 50 | 52 | ||
| 53 | #define AST_LUT_SIZE 256 | ||
| 54 | |||
| 51 | static inline void ast_load_palette_index(struct ast_private *ast, | 55 | static inline void ast_load_palette_index(struct ast_private *ast, |
| 52 | u8 index, u8 red, u8 green, | 56 | u8 index, u8 red, u8 green, |
| 53 | u8 blue) | 57 | u8 blue) |
| @@ -62,20 +66,46 @@ static inline void ast_load_palette_index(struct ast_private *ast, · 8 unmodified lines | |||
| 62 | ast_io_read8(ast, AST_IO_SEQ_PORT); | 66 | ast_io_read8(ast, AST_IO_SEQ_PORT); |
| 63 | } | 67 | } |
| 64 | 68 | ||
| 65 | static void ast_crtc_load_lut(struct ast_private *ast, struct drm_crtc *crtc) | 69 | static void ast_crtc_set_gamma_linear(struct ast_private *ast, |
| 70 | const struct drm_format_info *format) | ||
| 66 | { | 71 | { |
| 67 | u16 *r, *g, *b; | ||
| 68 | int i; | 72 | int i; |
| 69 | 73 | ||
| 70 | if (!crtc->enabled) | 74 | switch (format->format) { |
| 71 | return; | 75 | case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */ |
| 76 | case DRM_FORMAT_RGB565: | ||
| 77 | case DRM_FORMAT_XRGB8888: | ||
| 78 | for (i = 0; i < AST_LUT_SIZE; i++) | ||
| 79 | ast_load_palette_index(ast, i, i, i, i); | ||
| 80 | break; | ||
| 81 | default: | ||
| 82 | drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n", | ||
| 83 | &format->format); | ||
| 84 | break; | ||
| 85 | } | ||
| 86 | } | ||
| 72 | 87 | ||
| 73 | r = crtc->gamma_store; | 88 | static void ast_crtc_set_gamma(struct ast_private *ast, |
| 74 | g = r + crtc->gamma_size; | 89 | const struct drm_format_info *format, |
| 75 | b = g + crtc->gamma_size; | 90 | struct drm_color_lut *lut) |
| 91 | { | ||
| 92 | int i; | ||
| 76 | 93 | ||
| 77 | for (i = 0; i < 256; i++) | 94 | switch (format->format) { |
| 78 | ast_load_palette_index(ast, i, *r++ >> 8, *g++ >> 8, *b++ >> 8); | 95 | case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */ |
| 96 | case DRM_FORMAT_RGB565: | ||
| 97 | case DRM_FORMAT_XRGB8888: | ||
| 98 | for (i = 0; i < AST_LUT_SIZE; i++) | ||
| 99 | ast_load_palette_index(ast, i, | ||
| 100 | lut[i].red >> 8, | ||
| 101 | lut[i].green >> 8, | ||
| 102 | lut[i].blue >> 8); | ||
| 103 | break; | ||
| 104 | default: | ||
| 105 | drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n", | ||
| 106 | &format->format); | ||
| 107 | break; | ||
| 108 | } | ||
| 79 | } | 109 | } |
| 80 | 110 | ||
| 81 | static bool ast_get_vbios_mode_info(const struct drm_format_info *format, | 111 | static bool ast_get_vbios_mode_info(const struct drm_format_info *format, |
| @@ -537,6 +567,29 @@ static void ast_wait_for_vretrace(struct ast_private *ast) · 455 unmodified lines | |||
| 537 | } while (!(vgair1 & AST_IO_VGAIR1_VREFRESH) && time_before(jiffies, timeout)); | 567 | } while (!(vgair1 & AST_IO_VGAIR1_VREFRESH) && time_before(jiffies, timeout)); |
| 538 | } | 568 | } |
| 539 | 569 | ||
| 570 | /* | ||
| 571 | * Planes | ||
| 572 | */ | ||
| 573 | |||
| 574 | static int ast_plane_init(struct drm_device *dev, struct ast_plane *ast_plane, | ||
| 575 | void __iomem *vaddr, u64 offset, unsigned long size, | ||
| 576 | uint32_t possible_crtcs, | ||
| 577 | const struct drm_plane_funcs *funcs, | ||
| 578 | const uint32_t *formats, unsigned int format_count, | ||
| 579 | const uint64_t *format_modifiers, | ||
| 580 | enum drm_plane_type type) | ||
| 581 | { | ||
| 582 | struct drm_plane *plane = &ast_plane->base; | ||
| 583 | |||
| 584 | ast_plane->vaddr = vaddr; | ||
| 585 | ast_plane->offset = offset; | ||
| 586 | ast_plane->size = size; | ||
| 587 | |||
| 588 | return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, | ||
| 589 | formats, format_count, format_modifiers, | ||
| 590 | type, NULL); | ||
| 591 | } | ||
| 592 | |||
| 540 | /* | 593 | /* |
| 541 | * Primary plane | 594 | * Primary plane |
| 542 | */ | 595 | */ |
| @@ -550,52 +603,62 @@ static const uint32_t ast_primary_plane_formats[] = { · 7 unmodified lines | |||
| 550 | static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane, | 603 | static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane, |
| 551 | struct drm_atomic_state *state) | 604 | struct drm_atomic_state *state) |
| 552 | { | 605 | { |
| 553 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, | 606 | struct drm_device *dev = plane->dev; |
| 554 | plane); | 607 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); |
| 555 | struct drm_crtc_state *crtc_state; | 608 | struct drm_crtc_state *new_crtc_state = NULL; |
| 556 | struct ast_crtc_state *ast_crtc_state; | 609 | struct ast_crtc_state *new_ast_crtc_state; |
| 557 | int ret; | 610 | int ret; |
| 558 | 611 | ||
| 559 | if (!new_plane_state->crtc) | 612 | if (new_plane_state->crtc) |
| 560 | return 0; | 613 | new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); |
| 561 | |||
| 562 | crtc_state = drm_atomic_get_new_crtc_state(state, | ||
| 563 | new_plane_state->crtc); | ||
| 564 | 614 | ||
| 565 | ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, | 615 | ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, |
| 566 | DRM_PLANE_NO_SCALING, | 616 | DRM_PLANE_NO_SCALING, |
| 567 | DRM_PLANE_NO_SCALING, | 617 | DRM_PLANE_NO_SCALING, |
| 568 | false, true); | 618 | false, true); |
| 569 | if (ret) | 619 | if (ret) { |
| 570 | return ret; | 620 | return ret; |
| 621 | } else if (!new_plane_state->visible) { | ||
| 622 | if (drm_WARN_ON(dev, new_plane_state->crtc)) /* cannot legally happen */ | ||
| 623 | return -EINVAL; | ||
| 624 | else | ||
| 625 | return 0; | ||
| 626 | } | ||
| 571 | 627 | ||
| 572 | if (!new_plane_state->visible) | 628 | new_ast_crtc_state = to_ast_crtc_state(new_crtc_state); |
| 573 | return 0; | ||
| 574 | |||
| 575 | ast_crtc_state = to_ast_crtc_state(crtc_state); | ||
| 576 | 629 | ||
| 577 | ast_crtc_state->format = new_plane_state->fb->format; | 630 | new_ast_crtc_state->format = new_plane_state->fb->format; |
| 578 | 631 | ||
| 579 | return 0; | 632 | return 0; |
| 580 | } | 633 | } |
| 581 | 634 | ||
| 582 | static void | 635 | static void ast_handle_damage(struct ast_plane *ast_plane, struct iosys_map *src, |
| 583 | ast_primary_plane_helper_atomic_update(struct drm_plane *plane, | 636 | struct drm_framebuffer *fb, |
| 584 | struct drm_atomic_state *state) | 637 | const struct drm_rect *clip) |
| 638 | { | ||
| 639 | struct iosys_map dst = IOSYS_MAP_INIT_VADDR(ast_plane->vaddr); | ||
| 640 | |||
| 641 | iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip)); | ||
| 642 | drm_fb_memcpy(&dst, fb->pitches, src, fb, clip); | ||
| 643 | } | ||
| 644 | |||
| 645 | static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, | ||
| 646 | struct drm_atomic_state *state) | ||
| 585 | { | 647 | { |
| 586 | struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, | ||
| 587 | plane); | ||
| 588 | struct drm_device *dev = plane->dev; | 648 | struct drm_device *dev = plane->dev; |
| 589 | struct ast_private *ast = to_ast_private(dev); | 649 | struct ast_private *ast = to_ast_private(dev); |
| 590 | struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, | 650 | struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); |
| 591 | plane); | 651 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); |
| 592 | struct drm_gem_vram_object *gbo; | 652 | struct drm_framebuffer *fb = plane_state->fb; |
| 593 | s64 gpu_addr; | 653 | struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); |
| 594 | struct drm_framebuffer *fb = new_state->fb; | 654 | struct drm_framebuffer *old_fb = old_plane_state->fb; |
| 595 | struct drm_framebuffer *old_fb = old_state->fb; | 655 | struct ast_plane *ast_plane = to_ast_plane(plane); |
| 656 | struct drm_rect damage; | ||
| 657 | struct drm_atomic_helper_damage_iter iter; | ||
| 596 | 658 | ||
| 597 | if (!old_fb || (fb->format != old_fb->format)) { | 659 | if (!old_fb || (fb->format != old_fb->format)) { |
| 598 | struct drm_crtc_state *crtc_state = new_state->crtc->state; | 660 | struct drm_crtc *crtc = plane_state->crtc; |
| 661 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); | ||
| 599 | struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); | 662 | struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); |
| 600 | struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info; | 663 | struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info; |
| 601 | 664 | ||
| @@ -603,20 +666,28 @@ ast_primary_plane_helper_atomic_update(struct drm_plane *plane, · 1 unmodified line | |||
| 603 | ast_set_vbios_color_reg(ast, fb->format, vbios_mode_info); | 666 | ast_set_vbios_color_reg(ast, fb->format, vbios_mode_info); |
| 604 | } | 667 | } |
| 605 | 668 | ||
| 606 | gbo = drm_gem_vram_of_gem(fb->obj[0]); | 669 | drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); |
| 607 | gpu_addr = drm_gem_vram_offset(gbo); | 670 | drm_atomic_for_each_plane_damage(&iter, &damage) { |
| 608 | if (drm_WARN_ON_ONCE(dev, gpu_addr < 0)) | 671 | ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage); |
| 609 | return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */ | 672 | } |
| 610 | |||
| 611 | ast_set_offset_reg(ast, fb); | ||
| 612 | ast_set_start_address_crt1(ast, (u32)gpu_addr); | ||
| 613 | 673 | ||
| 614 | ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00); | 674 | /* |
| 675 | * Some BMCs stop scanning out the video signal after the driver | ||
| 676 | * reprogrammed the offset or scanout address. This stalls display | ||
| 677 | * output for several seconds and makes the display unusable. | ||
| 678 | * Therefore only update the offset if it changes and reprogram the | ||
| 679 | * address after enabling the plane. | ||
| 680 | */ | ||
| 681 | if (!old_fb || old_fb->pitches[0] != fb->pitches[0]) | ||
| 682 | ast_set_offset_reg(ast, fb); | ||
| 683 | if (!old_fb) { | ||
| 684 | ast_set_start_address_crt1(ast, (u32)ast_plane->offset); | ||
| 685 | ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00); | ||
| 686 | } | ||
| 615 | } | 687 | } |
| 616 | 688 | ||
| 617 | static void | 689 | static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, |
| 618 | ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, | 690 | struct drm_atomic_state *state) |
| 619 | struct drm_atomic_state *state) | ||
| 620 | { | 691 | { |
| 621 | struct ast_private *ast = to_ast_private(plane->dev); | 692 | struct ast_private *ast = to_ast_private(plane->dev); |
| 622 | 693 | ||
| @@ -624,7 +695,7 @@ ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, · 1 unmodified line | |||
| 624 | } | 695 | } |
| 625 | 696 | ||
| 626 | static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = { | 697 | static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = { |
| 627 | DRM_GEM_VRAM_PLANE_HELPER_FUNCS, | 698 | DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, |
| 628 | .atomic_check = ast_primary_plane_helper_atomic_check, | 699 | .atomic_check = ast_primary_plane_helper_atomic_check, |
| 629 | .atomic_update = ast_primary_plane_helper_atomic_update, | 700 | .atomic_update = ast_primary_plane_helper_atomic_update, |
| 630 | .atomic_disable = ast_primary_plane_helper_atomic_disable, | 701 | .atomic_disable = ast_primary_plane_helper_atomic_disable, |
| @@ -634,27 +705,30 @@ static const struct drm_plane_funcs ast_primary_plane_funcs = { · 3 unmodified lines | |||
| 634 | .update_plane = drm_atomic_helper_update_plane, | 705 | .update_plane = drm_atomic_helper_update_plane, |
| 635 | .disable_plane = drm_atomic_helper_disable_plane, | 706 | .disable_plane = drm_atomic_helper_disable_plane, |
| 636 | .destroy = drm_plane_cleanup, | 707 | .destroy = drm_plane_cleanup, |
| 637 | .reset = drm_atomic_helper_plane_reset, | 708 | DRM_GEM_SHADOW_PLANE_FUNCS, |
| 638 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
| 639 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
| 640 | }; | 709 | }; |
| 641 | 710 | ||
| 642 | static int ast_primary_plane_init(struct ast_private *ast) | 711 | static int ast_primary_plane_init(struct ast_private *ast) |
| 643 | { | 712 | { |
| 644 | struct drm_device *dev = &ast->base; | 713 | struct drm_device *dev = &ast->base; |
| 645 | struct drm_plane *primary_plane = &ast->primary_plane; | 714 | struct ast_plane *ast_primary_plane = &ast->primary_plane; |
| 715 | struct drm_plane *primary_plane = &ast_primary_plane->base; | ||
| 716 | void __iomem *vaddr = ast->vram; | ||
| 717 | u64 offset = ast->vram_base; | ||
| 718 | unsigned long cursor_size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); | ||
| 719 | unsigned long size = ast->vram_fb_available - cursor_size; | ||
| 646 | int ret; | 720 | int ret; |
| 647 | 721 | ||
| 648 | ret = drm_universal_plane_init(dev, primary_plane, 0x01, | 722 | ret = ast_plane_init(dev, ast_primary_plane, vaddr, offset, size, |
| 649 | &ast_primary_plane_funcs, | 723 | 0x01, &ast_primary_plane_funcs, |
| 650 | ast_primary_plane_formats, | 724 | ast_primary_plane_formats, ARRAY_SIZE(ast_primary_plane_formats), |
| 651 | ARRAY_SIZE(ast_primary_plane_formats), | 725 | NULL, DRM_PLANE_TYPE_PRIMARY); |
| 652 | NULL, DRM_PLANE_TYPE_PRIMARY, NULL); | ||
| 653 | if (ret) { | 726 | if (ret) { |
| 654 | drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); | 727 | drm_err(dev, "ast_plane_init() failed: %d\n", ret); |
| 655 | return ret; | 728 | return ret; |
| 656 | } | 729 | } |
| 657 | drm_plane_helper_add(primary_plane, &ast_primary_plane_helper_funcs); | 730 | drm_plane_helper_add(primary_plane, &ast_primary_plane_helper_funcs); |
| 731 | drm_plane_enable_fb_damage_clips(primary_plane); | ||
| 658 | 732 | ||
| 659 | return 0; | 733 | return 0; |
| 660 | } | 734 | } |
| @@ -774,99 +848,79 @@ static const uint32_t ast_cursor_plane_formats[] = { · 113 unmodified lines | |||
| 774 | static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane, | 848 | static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane, |
| 775 | struct drm_atomic_state *state) | 849 | struct drm_atomic_state *state) |
| 776 | { | 850 | { |
| 777 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, | 851 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); |
| 778 | plane); | 852 | struct drm_framebuffer *new_fb = new_plane_state->fb; |
| 779 | struct drm_framebuffer *fb = new_plane_state->fb; | 853 | struct drm_crtc_state *new_crtc_state = NULL; |
| 780 | struct drm_crtc_state *crtc_state; | ||
| 781 | int ret; | 854 | int ret; |
| 782 | 855 | ||
| 783 | if (!new_plane_state->crtc) | 856 | if (new_plane_state->crtc) |
| 784 | return 0; | 857 | new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); |
| 785 | |||
| 786 | crtc_state = drm_atomic_get_new_crtc_state(state, | ||
| 787 | new_plane_state->crtc); | ||
| 788 | 858 | ||
| 789 | ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, | 859 | ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, |
| 790 | DRM_PLANE_NO_SCALING, | 860 | DRM_PLANE_NO_SCALING, |
| 791 | DRM_PLANE_NO_SCALING, | 861 | DRM_PLANE_NO_SCALING, |
| 792 | true, true); | 862 | true, true); |
| 793 | if (ret) | 863 | if (ret || !new_plane_state->visible) |
| 794 | return ret; | 864 | return ret; |
| 795 | 865 | ||
| 796 | if (!new_plane_state->visible) | 866 | if (new_fb->width > AST_MAX_HWC_WIDTH || new_fb->height > AST_MAX_HWC_HEIGHT) |
| 797 | return 0; | ||
| 798 | |||
| 799 | if (fb->width > AST_MAX_HWC_WIDTH || fb->height > AST_MAX_HWC_HEIGHT) | ||
| 800 | return -EINVAL; | 867 | return -EINVAL; |
| 801 | 868 | ||
| 802 | return 0; | 869 | return 0; |
| 803 | } | 870 | } |
| 804 | 871 | ||
| 805 | static void | 872 | static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, |
| 806 | ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, | 873 | struct drm_atomic_state *state) |
| 807 | struct drm_atomic_state *state) | ||
| 808 | { | 874 | { |
| 809 | struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane); | 875 | struct ast_plane *ast_plane = to_ast_plane(plane); |
| 810 | struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, | 876 | struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); |
| 811 | plane); | 877 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); |
| 812 | struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, | 878 | struct drm_framebuffer *fb = plane_state->fb; |
| 813 | plane); | 879 | struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); |
| 814 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state); | ||
| 815 | struct drm_framebuffer *fb = new_state->fb; | ||
| 816 | struct ast_private *ast = to_ast_private(plane->dev); | 880 | struct ast_private *ast = to_ast_private(plane->dev); |
| 817 | struct iosys_map dst_map = | ||
| 818 | ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].map; | ||
| 819 | u64 dst_off = | ||
| 820 | ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].off; | ||
| 821 | struct iosys_map src_map = shadow_plane_state->data[0]; | 881 | struct iosys_map src_map = shadow_plane_state->data[0]; |
| 882 | struct drm_rect damage; | ||
| 883 | const u8 *src = src_map.vaddr; /* TODO: Use mapping abstraction properly */ | ||
| 884 | u64 dst_off = ast_plane->offset; | ||
| 885 | u8 __iomem *dst = ast_plane->vaddr; /* TODO: Use mapping abstraction properly */ | ||
| 886 | u8 __iomem *sig = dst + AST_HWC_SIZE; /* TODO: Use mapping abstraction properly */ | ||
| 822 | unsigned int offset_x, offset_y; | 887 | unsigned int offset_x, offset_y; |
| 823 | u16 x, y; | 888 | u16 x, y; |
| 824 | u8 x_offset, y_offset; | 889 | u8 x_offset, y_offset; |
| 825 | u8 __iomem *dst; | ||
| 826 | u8 __iomem *sig; | ||
| 827 | const u8 *src; | ||
| 828 | |||
| 829 | src = src_map.vaddr; /* TODO: Use mapping abstraction properly */ | ||
| 830 | dst = dst_map.vaddr_iomem; /* TODO: Use mapping abstraction properly */ | ||
| 831 | sig = dst + AST_HWC_SIZE; /* TODO: Use mapping abstraction properly */ | ||
| 832 | 890 | ||
| 833 | /* | 891 | /* |
| 834 | * Do data transfer to HW cursor BO. If a new cursor image was installed, | 892 | * Do data transfer to hardware buffer and point the scanout |
| 835 | * point the scanout engine to dst_gbo's offset and page-flip the HWC buffers. | 893 | * engine to the offset. |
| 836 | */ | 894 | */ |
| 837 | 895 | ||
| 838 | ast_update_cursor_image(dst, src, fb->width, fb->height); | 896 | if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &damage)) { |
| 839 | 897 | ast_update_cursor_image(dst, src, fb->width, fb->height); | |
| 840 | if (new_state->fb != old_state->fb) { | ||
| 841 | ast_set_cursor_base(ast, dst_off); | 898 | ast_set_cursor_base(ast, dst_off); |
| 842 | |||
| 843 | ++ast_cursor_plane->next_hwc_index; | ||
| 844 | ast_cursor_plane->next_hwc_index %= ARRAY_SIZE(ast_cursor_plane->hwc); | ||
| 845 | } | 899 | } |
| 846 | 900 | ||
| 847 | /* | 901 | /* |
| 848 | * Update location in HWC signature and registers. | 902 | * Update location in HWC signature and registers. |
| 849 | */ | 903 | */ |
| 850 | 904 | ||
| 851 | writel(new_state->crtc_x, sig + AST_HWC_SIGNATURE_X); | 905 | writel(plane_state->crtc_x, sig + AST_HWC_SIGNATURE_X); |
| 852 | writel(new_state->crtc_y, sig + AST_HWC_SIGNATURE_Y); | 906 | writel(plane_state->crtc_y, sig + AST_HWC_SIGNATURE_Y); |
| 853 | 907 | ||
| 854 | offset_x = AST_MAX_HWC_WIDTH - fb->width; | 908 | offset_x = AST_MAX_HWC_WIDTH - fb->width; |
| 855 | offset_y = AST_MAX_HWC_HEIGHT - fb->height; | 909 | offset_y = AST_MAX_HWC_HEIGHT - fb->height; |
| 856 | 910 | ||
| 857 | if (new_state->crtc_x < 0) { | 911 | if (plane_state->crtc_x < 0) { |
| 858 | x_offset = (-new_state->crtc_x) + offset_x; | 912 | x_offset = (-plane_state->crtc_x) + offset_x; |
| 859 | x = 0; | 913 | x = 0; |
| 860 | } else { | 914 | } else { |
| 861 | x_offset = offset_x; | 915 | x_offset = offset_x; |
| 862 | x = new_state->crtc_x; | 916 | x = plane_state->crtc_x; |
| 863 | } | 917 | } |
| 864 | if (new_state->crtc_y < 0) { | 918 | if (plane_state->crtc_y < 0) { |
| 865 | y_offset = (-new_state->crtc_y) + offset_y; | 919 | y_offset = (-plane_state->crtc_y) + offset_y; |
| 866 | y = 0; | 920 | y = 0; |
| 867 | } else { | 921 | } else { |
| 868 | y_offset = offset_y; | 922 | y_offset = offset_y; |
| 869 | y = new_state->crtc_y; | 923 | y = plane_state->crtc_y; |
| 870 | } | 924 | } |
| 871 | 925 | ||
| 872 | ast_set_cursor_location(ast, x, y, x_offset, y_offset); | 926 | ast_set_cursor_location(ast, x, y, x_offset, y_offset); |
| @@ -875,9 +929,8 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, · 2 unmodified lines | |||
| 875 | ast_set_cursor_enabled(ast, true); | 929 | ast_set_cursor_enabled(ast, true); |
| 876 | } | 930 | } |
| 877 | 931 | ||
| 878 | static void | 932 | static void ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane, |
| 879 | ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane, | 933 | struct drm_atomic_state *state) |
| 880 | struct drm_atomic_state *state) | ||
| 881 | { | 934 | { |
| 882 | struct ast_private *ast = to_ast_private(plane->dev); | 935 | struct ast_private *ast = to_ast_private(plane->dev); |
| 883 | 936 | ||
| @@ -891,41 +944,22 @@ static const struct drm_plane_helper_funcs ast_cursor_plane_helper_funcs = { · 7 unmodified lines | |||
| 891 | .atomic_disable = ast_cursor_plane_helper_atomic_disable, | 944 | .atomic_disable = ast_cursor_plane_helper_atomic_disable, |
| 892 | }; | 945 | }; |
| 893 | 946 | ||
| 894 | static void ast_cursor_plane_destroy(struct drm_plane *plane) | ||
| 895 | { | ||
| 896 | struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane); | ||
| 897 | size_t i; | ||
| 898 | struct drm_gem_vram_object *gbo; | ||
| 899 | struct iosys_map map; | ||
| 900 | |||
| 901 | for (i = 0; i < ARRAY_SIZE(ast_cursor_plane->hwc); ++i) { | ||
| 902 | gbo = ast_cursor_plane->hwc[i].gbo; | ||
| 903 | map = ast_cursor_plane->hwc[i].map; | ||
| 904 | drm_gem_vram_vunmap(gbo, &map); | ||
| 905 | drm_gem_vram_unpin(gbo); | ||
| 906 | drm_gem_vram_put(gbo); | ||
| 907 | } | ||
| 908 | |||
| 909 | drm_plane_cleanup(plane); | ||
| 910 | } | ||
| 911 | |||
| 912 | static const struct drm_plane_funcs ast_cursor_plane_funcs = { | 947 | static const struct drm_plane_funcs ast_cursor_plane_funcs = { |
| 913 | .update_plane = drm_atomic_helper_update_plane, | 948 | .update_plane = drm_atomic_helper_update_plane, |
| 914 | .disable_plane = drm_atomic_helper_disable_plane, | 949 | .disable_plane = drm_atomic_helper_disable_plane, |
| 915 | .destroy = ast_cursor_plane_destroy, | 950 | .destroy = drm_plane_cleanup, |
| 916 | DRM_GEM_SHADOW_PLANE_FUNCS, | 951 | DRM_GEM_SHADOW_PLANE_FUNCS, |
| 917 | }; | 952 | }; |
| 918 | 953 | ||
| 919 | static int ast_cursor_plane_init(struct ast_private *ast) | 954 | static int ast_cursor_plane_init(struct ast_private *ast) |
| 920 | { | 955 | { |
| 921 | struct drm_device *dev = &ast->base; | 956 | struct drm_device *dev = &ast->base; |
| 922 | struct ast_cursor_plane *ast_cursor_plane = &ast->cursor_plane; | 957 | struct ast_plane *ast_cursor_plane = &ast->cursor_plane; |
| 923 | struct drm_plane *cursor_plane = &ast_cursor_plane->base; | 958 | struct drm_plane *cursor_plane = &ast_cursor_plane->base; |
| 924 | size_t size, i; | 959 | size_t size; |
| 925 | struct drm_gem_vram_object *gbo; | 960 | void __iomem *vaddr; |
| 926 | struct iosys_map map; | 961 | u64 offset; |
| 927 | int ret; | 962 | int ret; |
| 928 | s64 off; | ||
| 929 | 963 | ||
| 930 | /* | 964 | /* |
| 931 | * Allocate backing storage for cursors. The BOs are permanently | 965 | * Allocate backing storage for cursors. The BOs are permanently |
| @@ -934,60 +968,26 @@ static int ast_cursor_plane_init(struct ast_private *ast) · 2 unmodified lines | |||
| 934 | 968 | ||
| 935 | size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); | 969 | size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); |
| 936 | 970 | ||
| 937 | for (i = 0; i < ARRAY_SIZE(ast_cursor_plane->hwc); ++i) { | 971 | if (ast->vram_fb_available < size) |
| 938 | gbo = drm_gem_vram_create(dev, size, 0); | 972 | return -ENOMEM; |
| 939 | if (IS_ERR(gbo)) { | ||
| 940 | ret = PTR_ERR(gbo); | ||
| 941 | goto err_hwc; | ||
| 942 | } | ||
| 943 | ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM | | ||
| 944 | DRM_GEM_VRAM_PL_FLAG_TOPDOWN); | ||
| 945 | if (ret) | ||
| 946 | goto err_drm_gem_vram_put; | ||
| 947 | ret = drm_gem_vram_vmap(gbo, &map); | ||
| 948 | if (ret) | ||
| 949 | goto err_drm_gem_vram_unpin; | ||
| 950 | off = drm_gem_vram_offset(gbo); | ||
| 951 | if (off < 0) { | ||
| 952 | ret = off; | ||
| 953 | goto err_drm_gem_vram_vunmap; | ||
| 954 | } | ||
| 955 | ast_cursor_plane->hwc[i].gbo = gbo; | ||
| 956 | ast_cursor_plane->hwc[i].map = map; | ||
| 957 | ast_cursor_plane->hwc[i].off = off; | ||
| 958 | } | ||
| 959 | 973 | ||
| 960 | /* | 974 | vaddr = ast->vram + ast->vram_fb_available - size; |
| 961 | * Create the cursor plane. The plane's destroy callback will release | 975 | offset = ast->vram_base + ast->vram_fb_available - size; |
| 962 | * the backing storages' BO memory. | ||
| 963 | */ | ||
| 964 | 976 | ||
| 965 | ret = drm_universal_plane_init(dev, cursor_plane, 0x01, | 977 | ret = ast_plane_init(dev, ast_cursor_plane, vaddr, offset, size, |
| 966 | &ast_cursor_plane_funcs, | 978 | 0x01, &ast_cursor_plane_funcs, |
| 967 | ast_cursor_plane_formats, | 979 | ast_cursor_plane_formats, ARRAY_SIZE(ast_cursor_plane_formats), |
| 968 | ARRAY_SIZE(ast_cursor_plane_formats), | 980 | NULL, DRM_PLANE_TYPE_CURSOR); |
| 969 | NULL, DRM_PLANE_TYPE_CURSOR, NULL); | ||
| 970 | if (ret) { | 981 | if (ret) { |
| 971 | drm_err(dev, "drm_universal_plane failed(): %d\n", ret); | 982 | drm_err(dev, "ast_plane_init() failed: %d\n", ret); |
| 972 | goto err_hwc; | 983 | return ret; |
| 973 | } | 984 | } |
| 974 | drm_plane_helper_add(cursor_plane, &ast_cursor_plane_helper_funcs); | 985 | drm_plane_helper_add(cursor_plane, &ast_cursor_plane_helper_funcs); |
| 986 | drm_plane_enable_fb_damage_clips(cursor_plane); | ||
| 975 | 987 | ||
| 976 | return 0; | 988 | ast->vram_fb_available -= size; |
| 977 | 989 | ||
| 978 | err_hwc: | 990 | return 0; |
| 979 | while (i) { | ||
| 980 | --i; | ||
| 981 | gbo = ast_cursor_plane->hwc[i].gbo; | ||
| 982 | map = ast_cursor_plane->hwc[i].map; | ||
| 983 | err_drm_gem_vram_vunmap: | ||
| 984 | drm_gem_vram_vunmap(gbo, &map); | ||
| 985 | err_drm_gem_vram_unpin: | ||
| 986 | drm_gem_vram_unpin(gbo); | ||
| 987 | err_drm_gem_vram_put: | ||
| 988 | drm_gem_vram_put(gbo); | ||
| 989 | } | ||
| 990 | return ret; | ||
| 991 | } | 991 | } |
| 992 | 992 | ||
| 993 | /* | 993 | /* |
| @@ -1026,9 +1026,11 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) · 32 unmodified lines | |||
| 1026 | 1026 | ||
| 1027 | ast_set_color_reg(ast, format); | 1027 | ast_set_color_reg(ast, format); |
| 1028 | ast_set_vbios_color_reg(ast, format, vbios_mode_info); | 1028 | ast_set_vbios_color_reg(ast, format, vbios_mode_info); |
| 1029 | if (crtc->state->gamma_lut) | ||
| 1030 | ast_crtc_set_gamma(ast, format, crtc->state->gamma_lut->data); | ||
| 1031 | else | ||
| 1032 | ast_crtc_set_gamma_linear(ast, format); | ||
| 1029 | } | 1033 | } |
| 1030 | |||
| 1031 | ast_crtc_load_lut(ast, crtc); | ||
| 1032 | break; | 1034 | break; |
| 1033 | case DRM_MODE_DPMS_STANDBY: | 1035 | case DRM_MODE_DPMS_STANDBY: |
| 1034 | case DRM_MODE_DPMS_SUSPEND: | 1036 | case DRM_MODE_DPMS_SUSPEND: |
| @@ -1123,47 +1125,50 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, · 88 unmodified lines | |||
| 1123 | struct drm_atomic_state *state) | 1125 | struct drm_atomic_state *state) |
| 1124 | { | 1126 | { |
| 1125 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); | 1127 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); |
| 1128 | struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); | ||
| 1129 | struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state); | ||
| 1126 | struct drm_device *dev = crtc->dev; | 1130 | struct drm_device *dev = crtc->dev; |
| 1127 | struct ast_crtc_state *ast_state; | 1131 | struct ast_crtc_state *ast_state; |
| 1128 | const struct drm_format_info *format; | 1132 | const struct drm_format_info *format; |
| 1129 | bool succ; | 1133 | bool succ; |
| 1130 | int ret; | 1134 | int ret; |
| 1131 | 1135 | ||
| 1132 | ret = drm_atomic_helper_check_crtc_state(crtc_state, false); | 1136 | if (!crtc_state->enable) |
| 1137 | return 0; | ||
| 1138 | |||
| 1139 | ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); | ||
| 1133 | if (ret) | 1140 | if (ret) |
| 1134 | return ret; | 1141 | return ret; |
| 1135 | 1142 | ||
| 1136 | if (!crtc_state->enable) | ||
| 1137 | goto out; | ||
| 1138 | |||
| 1139 | ast_state = to_ast_crtc_state(crtc_state); | 1143 | ast_state = to_ast_crtc_state(crtc_state); |
| 1140 | 1144 | ||
| 1141 | format = ast_state->format; | 1145 | format = ast_state->format; |
| 1142 | if (drm_WARN_ON_ONCE(dev, !format)) | 1146 | if (drm_WARN_ON_ONCE(dev, !format)) |
| 1143 | return -EINVAL; /* BUG: We didn't set format in primary check(). */ | 1147 | return -EINVAL; /* BUG: We didn't set format in primary check(). */ |
| 1144 | 1148 | ||
| 1149 | /* | ||
| 1150 | * The gamma LUT has to be reloaded after changing the primary | ||
| 1151 | * plane's color format. | ||
| 1152 | */ | ||
| 1153 | if (old_ast_crtc_state->format != format) | ||
| 1154 | crtc_state->color_mgmt_changed = true; | ||
| 1155 | |||
| 1156 | if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) { | ||
| 1157 | if (crtc_state->gamma_lut->length != | ||
| 1158 | AST_LUT_SIZE * sizeof(struct drm_color_lut)) { | ||
| 1159 | drm_err(dev, "Wrong size for gamma_lut %zu\n", | ||
| 1160 | crtc_state->gamma_lut->length); | ||
| 1161 | return -EINVAL; | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | |||
| 1145 | succ = ast_get_vbios_mode_info(format, &crtc_state->mode, | 1165 | succ = ast_get_vbios_mode_info(format, &crtc_state->mode, |
| 1146 | &crtc_state->adjusted_mode, | 1166 | &crtc_state->adjusted_mode, |
| 1147 | &ast_state->vbios_mode_info); | 1167 | &ast_state->vbios_mode_info); |
| 1148 | if (!succ) | 1168 | if (!succ) |
| 1149 | return -EINVAL; | 1169 | return -EINVAL; |
| 1150 | 1170 | ||
| 1151 | out: | 1171 | return 0; |
| 1152 | return drm_atomic_add_affected_planes(state, crtc); | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | static void ast_crtc_helper_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state) | ||
| 1156 | { | ||
| 1157 | struct drm_device *dev = crtc->dev; | ||
| 1158 | struct ast_private *ast = to_ast_private(dev); | ||
| 1159 | |||
| 1160 | /* | ||
| 1161 | * Concurrent operations could possibly trigger a call to | ||
| 1162 | * drm_connector_helper_funcs.get_modes by trying to read the | ||
| 1163 | * display modes. Protect access to I/O registers by acquiring | ||
| 1164 | * the I/O-register lock. Released in atomic_flush(). | ||
| 1165 | */ | ||
| 1166 | mutex_lock(&ast->ioregs_lock); | ||
| 1167 | } | 1172 | } |
| 1168 | 1173 | ||
| 1169 | static void | 1174 | static void |
| @@ -1172,35 +1177,34 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, · 2 unmodified lines | |||
| 1172 | { | 1177 | { |
| 1173 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, | 1178 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, |
| 1174 | crtc); | 1179 | crtc); |
| 1175 | struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, | ||
| 1176 | crtc); | ||
| 1177 | struct drm_device *dev = crtc->dev; | 1180 | struct drm_device *dev = crtc->dev; |
| 1178 | struct ast_private *ast = to_ast_private(dev); | 1181 | struct ast_private *ast = to_ast_private(dev); |
| 1179 | struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); | 1182 | struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); |
| 1180 | struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state); | ||
| 1181 | struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info; | 1183 | struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info; |
| 1182 | 1184 | ||
| 1183 | /* | 1185 | /* |
| 1184 | * The gamma LUT has to be reloaded after changing the primary | 1186 | * The gamma LUT has to be reloaded after changing the primary |
| 1185 | * plane's color format. | 1187 | * plane's color format. |
| 1186 | */ | 1188 | */ |
| 1187 | if (old_ast_crtc_state->format != ast_crtc_state->format) | 1189 | if (crtc_state->enable && crtc_state->color_mgmt_changed) { |
| 1188 | ast_crtc_load_lut(ast, crtc); | 1190 | if (crtc_state->gamma_lut) |
| 1191 | ast_crtc_set_gamma(ast, | ||
| 1192 | ast_crtc_state->format, | ||
| 1193 | crtc_state->gamma_lut->data); | ||
| 1194 | else | ||
| 1195 | ast_crtc_set_gamma_linear(ast, ast_crtc_state->format); | ||
| 1196 | } | ||
| 1189 | 1197 | ||
| 1190 | //Set Aspeed Display-Port | 1198 | //Set Aspeed Display-Port |
| 1191 | if (ast->tx_chip_types & AST_TX_ASTDP_BIT) | 1199 | if (ast->tx_chip_types & AST_TX_ASTDP_BIT) |
| 1192 | ast_dp_set_mode(crtc, vbios_mode_info); | 1200 | ast_dp_set_mode(crtc, vbios_mode_info); |
| 1193 | |||
| 1194 | mutex_unlock(&ast->ioregs_lock); | ||
| 1195 | } | 1201 | } |
| 1196 | 1202 | ||
| 1197 | static void | 1203 | static void ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) |
| 1198 | ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, | ||
| 1199 | struct drm_atomic_state *state) | ||
| 1200 | { | 1204 | { |
| 1201 | struct drm_device *dev = crtc->dev; | 1205 | struct drm_device *dev = crtc->dev; |
| 1202 | struct ast_private *ast = to_ast_private(dev); | 1206 | struct ast_private *ast = to_ast_private(dev); |
| 1203 | struct drm_crtc_state *crtc_state = crtc->state; | 1207 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); |
| 1204 | struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); | 1208 | struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); |
| 1205 | struct ast_vbios_mode_info *vbios_mode_info = | 1209 | struct ast_vbios_mode_info *vbios_mode_info = |
| 1206 | &ast_crtc_state->vbios_mode_info; | 1210 | &ast_crtc_state->vbios_mode_info; |
| @@ -1217,12 +1221,9 @@ ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, · 10 unmodified lines | |||
| 1217 | ast_crtc_dpms(crtc, DRM_MODE_DPMS_ON); | 1221 | ast_crtc_dpms(crtc, DRM_MODE_DPMS_ON); |
| 1218 | } | 1222 | } |
| 1219 | 1223 | ||
| 1220 | static void | 1224 | static void ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) |
| 1221 | ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, | ||
| 1222 | struct drm_atomic_state *state) | ||
| 1223 | { | 1225 | { |
| 1224 | struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, | 1226 | struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); |
| 1225 | crtc); | ||
| 1226 | struct drm_device *dev = crtc->dev; | 1227 | struct drm_device *dev = crtc->dev; |
| 1227 | struct ast_private *ast = to_ast_private(dev); | 1228 | struct ast_private *ast = to_ast_private(dev); |
| 1228 | 1229 | ||
| @@ -1250,7 +1251,6 @@ ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, · 21 unmodified lines | |||
| 1250 | static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = { | 1251 | static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = { |
| 1251 | .mode_valid = ast_crtc_helper_mode_valid, | 1252 | .mode_valid = ast_crtc_helper_mode_valid, |
| 1252 | .atomic_check = ast_crtc_helper_atomic_check, | 1253 | .atomic_check = ast_crtc_helper_atomic_check, |
| 1253 | .atomic_begin = ast_crtc_helper_atomic_begin, | ||
| 1254 | .atomic_flush = ast_crtc_helper_atomic_flush, | 1254 | .atomic_flush = ast_crtc_helper_atomic_flush, |
| 1255 | .atomic_enable = ast_crtc_helper_atomic_enable, | 1255 | .atomic_enable = ast_crtc_helper_atomic_enable, |
| 1256 | .atomic_disable = ast_crtc_helper_atomic_disable, | 1256 | .atomic_disable = ast_crtc_helper_atomic_disable, |
| @@ -1317,13 +1317,15 @@ static int ast_crtc_init(struct drm_device *dev) · 60 unmodified lines | |||
| 1317 | struct drm_crtc *crtc = &ast->crtc; | 1317 | struct drm_crtc *crtc = &ast->crtc; |
| 1318 | int ret; | 1318 | int ret; |
| 1319 | 1319 | ||
| 1320 | ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane, | 1320 | ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane.base, |
| 1321 | &ast->cursor_plane.base, &ast_crtc_funcs, | 1321 | &ast->cursor_plane.base, &ast_crtc_funcs, |
| 1322 | NULL); | 1322 | NULL); |
| 1323 | if (ret) | 1323 | if (ret) |
| 1324 | return ret; | 1324 | return ret; |
| 1325 | 1325 | ||
| 1326 | drm_mode_crtc_set_gamma_size(crtc, 256); | 1326 | drm_mode_crtc_set_gamma_size(crtc, AST_LUT_SIZE); |
| 1327 | drm_crtc_enable_color_mgmt(crtc, 0, false, AST_LUT_SIZE); | ||
| 1328 | |||
| 1327 | drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs); | 1329 | drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs); |
| 1328 | 1330 | ||
| 1329 | return 0; | 1331 | return 0; |
| @@ -1718,13 +1720,46 @@ static int ast_astdp_output_init(struct ast_private *ast) · 388 unmodified lines | |||
| 1718 | * Mode config | 1720 | * Mode config |
| 1719 | */ | 1721 | */ |
| 1720 | 1722 | ||
| 1723 | static void ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state) | ||
| 1724 | { | ||
| 1725 | struct ast_private *ast = to_ast_private(state->dev); | ||
| 1726 | |||
| 1727 | /* | ||
| 1728 | * Concurrent operations could possibly trigger a call to | ||
| 1729 | * drm_connector_helper_funcs.get_modes by trying to read the | ||
| 1730 | * display modes. Protect access to I/O registers by acquiring | ||
| 1731 | * the I/O-register lock. Released in atomic_flush(). | ||
| 1732 | */ | ||
| 1733 | mutex_lock(&ast->ioregs_lock); | ||
| 1734 | drm_atomic_helper_commit_tail_rpm(state); | ||
| 1735 | mutex_unlock(&ast->ioregs_lock); | ||
| 1736 | } | ||
| 1737 | |||
| 1721 | static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = { | 1738 | static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = { |
| 1722 | .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, | 1739 | .atomic_commit_tail = ast_mode_config_helper_atomic_commit_tail, |
| 1723 | }; | 1740 | }; |
| 1724 | 1741 | ||
| 1742 | static enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev, | ||
| 1743 | const struct drm_display_mode *mode) | ||
| 1744 | { | ||
| 1745 | static const unsigned long max_bpp = 4; /* DRM_FORMAT_XRGB8888 */ | ||
| 1746 | struct ast_private *ast = to_ast_private(dev); | ||
| 1747 | unsigned long fbsize, fbpages, max_fbpages; | ||
| 1748 | |||
| 1749 | max_fbpages = (ast->vram_fb_available) >> PAGE_SHIFT; | ||
| 1750 | |||
| 1751 | fbsize = mode->hdisplay * mode->vdisplay * max_bpp; | ||
| 1752 | fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE); | ||
| 1753 | |||
| 1754 | if (fbpages > max_fbpages) | ||
| 1755 | return MODE_MEM; | ||
| 1756 | |||
| 1757 | return MODE_OK; | ||
| 1758 | } | ||
| 1759 | |||
| 1725 | static const struct drm_mode_config_funcs ast_mode_config_funcs = { | 1760 | static const struct drm_mode_config_funcs ast_mode_config_funcs = { |
| 1726 | .fb_create = drm_gem_fb_create, | 1761 | .fb_create = drm_gem_fb_create_with_dirty, |
| 1727 | .mode_valid = drm_vram_helper_mode_valid, | 1762 | .mode_valid = ast_mode_config_mode_valid, |
| 1728 | .atomic_check = drm_atomic_helper_check, | 1763 | .atomic_check = drm_atomic_helper_check, |
| 1729 | .atomic_commit = drm_atomic_helper_commit, | 1764 | .atomic_commit = drm_atomic_helper_commit, |
| 1730 | }; | 1765 | }; |
| @@ -1732,7 +1767,6 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = { · 1 unmodified line | |||
| 1732 | int ast_mode_config_init(struct ast_private *ast) | 1767 | int ast_mode_config_init(struct ast_private *ast) |
| 1733 | { | 1768 | { |
| 1734 | struct drm_device *dev = &ast->base; | 1769 | struct drm_device *dev = &ast->base; |
| 1735 | struct pci_dev *pdev = to_pci_dev(dev->dev); | ||
| 1736 | int ret; | 1770 | int ret; |
| 1737 | 1771 | ||
| 1738 | ret = drmm_mode_config_init(dev); | 1772 | ret = drmm_mode_config_init(dev); |
| @@ -1743,8 +1777,6 @@ int ast_mode_config_init(struct ast_private *ast) · 4 unmodified lines | |||
| 1743 | dev->mode_config.min_width = 0; | 1777 | dev->mode_config.min_width = 0; |
| 1744 | dev->mode_config.min_height = 0; | 1778 | dev->mode_config.min_height = 0; |
| 1745 | dev->mode_config.preferred_depth = 24; | 1779 | dev->mode_config.preferred_depth = 24; |
| 1746 | dev->mode_config.prefer_shadow = 1; | ||
| 1747 | dev->mode_config.fb_base = pci_resource_start(pdev, 0); | ||
| 1748 | 1780 | ||
| 1749 | if (ast->chip == AST2100 || | 1781 | if (ast->chip == AST2100 || |
| 1750 | ast->chip == AST2200 || | 1782 | ast->chip == AST2200 || |
| @@ -1761,7 +1793,6 @@ int ast_mode_config_init(struct ast_private *ast) · 10 unmodified lines | |||
| 1761 | 1793 | ||
| 1762 | dev->mode_config.helper_private = &ast_mode_config_helper_funcs; | 1794 | dev->mode_config.helper_private = &ast_mode_config_helper_funcs; |
| 1763 | 1795 | ||
| 1764 | |||
| 1765 | ret = ast_primary_plane_init(ast); | 1796 | ret = ast_primary_plane_init(ast); |
| 1766 | if (ret) | 1797 | if (ret) |
| 1767 | return ret; | 1798 | return ret; |
| @@ -402,7 +402,8 @@ static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511) · 401 unmodified lines | |||
| 402 | 402 | ||
| 403 | void adv7533_dsi_power_on(struct adv7511 *adv); | 403 | void adv7533_dsi_power_on(struct adv7511 *adv); |
| 404 | void adv7533_dsi_power_off(struct adv7511 *adv); | 404 | void adv7533_dsi_power_off(struct adv7511 *adv); |
| 405 | void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode); | 405 | enum drm_mode_status adv7533_mode_valid(struct adv7511 *adv, |
| 406 | const struct drm_display_mode *mode); | ||
| 406 | int adv7533_patch_registers(struct adv7511 *adv); | 407 | int adv7533_patch_registers(struct adv7511 *adv); |
| 407 | int adv7533_patch_cec_registers(struct adv7511 *adv); | 408 | int adv7533_patch_cec_registers(struct adv7511 *adv); |
| 408 | int adv7533_attach_dsi(struct adv7511 *adv); | 409 | int adv7533_attach_dsi(struct adv7511 *adv); |
| @@ -697,7 +697,7 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) · 696 unmodified lines | |||
| 697 | } | 697 | } |
| 698 | 698 | ||
| 699 | static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511, | 699 | static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511, |
| 700 | struct drm_display_mode *mode) | 700 | const struct drm_display_mode *mode) |
| 701 | { | 701 | { |
| 702 | if (mode->clock > 165000) | 702 | if (mode->clock > 165000) |
| 703 | return MODE_CLOCK_HIGH; | 703 | return MODE_CLOCK_HIGH; |
| @@ -791,9 +791,6 @@ static void adv7511_mode_set(struct adv7511 *adv7511, · 87 unmodified lines | |||
| 791 | regmap_update_bits(adv7511->regmap, 0x17, | 791 | regmap_update_bits(adv7511->regmap, 0x17, |
| 792 | 0x60, (vsync_polarity << 6) | (hsync_polarity << 5)); | 792 | 0x60, (vsync_polarity << 6) | (hsync_polarity << 5)); |
| 793 | 793 | ||
| 794 | if (adv7511->type == ADV7533 || adv7511->type == ADV7535) | ||
| 795 | adv7533_mode_set(adv7511, adj_mode); | ||
| 796 | |||
| 797 | drm_mode_copy(&adv7511->curr_mode, adj_mode); | 794 | drm_mode_copy(&adv7511->curr_mode, adj_mode); |
| 798 | 795 | ||
| 799 | /* | 796 | /* |
| @@ -913,6 +910,18 @@ static void adv7511_bridge_mode_set(struct drm_bridge *bridge, · 113 unmodified lines | |||
| 913 | adv7511_mode_set(adv, mode, adj_mode); | 910 | adv7511_mode_set(adv, mode, adj_mode); |
| 914 | } | 911 | } |
| 915 | 912 | ||
| 913 | static enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge, | ||
| 914 | const struct drm_display_info *info, | ||
| 915 | const struct drm_display_mode *mode) | ||
| 916 | { | ||
| 917 | struct adv7511 *adv = bridge_to_adv7511(bridge); | ||
| 918 | |||
| 919 | if (adv->type == ADV7533 || adv->type == ADV7535) | ||
| 920 | return adv7533_mode_valid(adv, mode); | ||
| 921 | else | ||
| 922 | return adv7511_mode_valid(adv, mode); | ||
| 923 | } | ||
| 924 | |||
| 916 | static int adv7511_bridge_attach(struct drm_bridge *bridge, | 925 | static int adv7511_bridge_attach(struct drm_bridge *bridge, |
| 917 | enum drm_bridge_attach_flags flags) | 926 | enum drm_bridge_attach_flags flags) |
| 918 | { | 927 | { |
| @@ -960,6 +969,7 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = { · 41 unmodified lines | |||
| 960 | .enable = adv7511_bridge_enable, | 969 | .enable = adv7511_bridge_enable, |
| 961 | .disable = adv7511_bridge_disable, | 970 | .disable = adv7511_bridge_disable, |
| 962 | .mode_set = adv7511_bridge_mode_set, | 971 | .mode_set = adv7511_bridge_mode_set, |
| 972 | .mode_valid = adv7511_bridge_mode_valid, | ||
| 963 | .attach = adv7511_bridge_attach, | 973 | .attach = adv7511_bridge_attach, |
| 964 | .detect = adv7511_bridge_detect, | 974 | .detect = adv7511_bridge_detect, |
| 965 | .get_edid = adv7511_bridge_get_edid, | 975 | .get_edid = adv7511_bridge_get_edid, |
| @@ -100,26 +100,27 @@ void adv7533_dsi_power_off(struct adv7511 *adv) · 99 unmodified lines | |||
| 100 | regmap_write(adv->regmap_cec, 0x27, 0x0b); | 100 | regmap_write(adv->regmap_cec, 0x27, 0x0b); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode) | 103 | enum drm_mode_status adv7533_mode_valid(struct adv7511 *adv, |
| 104 | const struct drm_display_mode *mode) | ||
| 104 | { | 105 | { |
| 106 | int lanes; | ||
| 105 | struct mipi_dsi_device *dsi = adv->dsi; | 107 | struct mipi_dsi_device *dsi = adv->dsi; |
| 106 | int lanes, ret; | ||
| 107 | |||
| 108 | if (adv->num_dsi_lanes != 4) | ||
| 109 | return; | ||
| 110 | 108 | ||
| 111 | if (mode->clock > 80000) | 109 | if (mode->clock > 80000) |
| 112 | lanes = 4; | 110 | lanes = 4; |
| 113 | else | 111 | else |
| 114 | lanes = 3; | 112 | lanes = 3; |
| 115 | 113 | ||
| 116 | if (lanes != dsi->lanes) { | 114 | /* |
| 117 | mipi_dsi_detach(dsi); | 115 | * TODO: add support for dynamic switching of lanes |
| 118 | dsi->lanes = lanes; | 116 | * by using the bridge pre_enable() op . Till then filter |
| 119 | ret = mipi_dsi_attach(dsi); | 117 | * out the modes which shall need different number of lanes |
| 120 | if (ret) | 118 | * than what was configured in the device tree. |
| 121 | dev_err(&dsi->dev, "failed to change host lanes\n"); | 119 | */ |
| 122 | } | 120 | if (lanes != dsi->lanes) |
| 121 | return MODE_BAD; | ||
| 122 | |||
| 123 | return MODE_OK; | ||
| 123 | } | 124 | } |
| 124 | 125 | ||
| 125 | int adv7533_patch_registers(struct adv7511 *adv) | 126 | int adv7533_patch_registers(struct adv7511 *adv) |
| @@ -421,6 +421,7 @@ struct it6505 { · 420 unmodified lines | |||
| 421 | struct notifier_block event_nb; | 421 | struct notifier_block event_nb; |
| 422 | struct extcon_dev *extcon; | 422 | struct extcon_dev *extcon; |
| 423 | struct work_struct extcon_wq; | 423 | struct work_struct extcon_wq; |
| 424 | int extcon_state; | ||
| 424 | enum drm_connector_status connector_status; | 425 | enum drm_connector_status connector_status; |
| 425 | enum link_train_status link_state; | 426 | enum link_train_status link_state; |
| 426 | struct work_struct link_works; | 427 | struct work_struct link_works; |
| @@ -2685,31 +2686,41 @@ static void it6505_extcon_work(struct work_struct *work) · 2258 unmodified lines | |||
| 2685 | { | 2686 | { |
| 2686 | struct it6505 *it6505 = container_of(work, struct it6505, extcon_wq); | 2687 | struct it6505 *it6505 = container_of(work, struct it6505, extcon_wq); |
| 2687 | struct device *dev = &it6505->client->dev; | 2688 | struct device *dev = &it6505->client->dev; |
| 2688 | int state = extcon_get_state(it6505->extcon, EXTCON_DISP_DP); | 2689 | int state, ret; |
| 2689 | unsigned int pwroffretry = 0; | ||
| 2690 | 2690 | ||
| 2691 | if (it6505->enable_drv_hold) | 2691 | if (it6505->enable_drv_hold) |
| 2692 | return; | 2692 | return; |
| 2693 | 2693 | ||
| 2694 | mutex_lock(&it6505->extcon_lock); | 2694 | mutex_lock(&it6505->extcon_lock); |
| 2695 | 2695 | ||
| 2696 | state = extcon_get_state(it6505->extcon, EXTCON_DISP_DP); | ||
| 2696 | DRM_DEV_DEBUG_DRIVER(dev, "EXTCON_DISP_DP = 0x%02x", state); | 2697 | DRM_DEV_DEBUG_DRIVER(dev, "EXTCON_DISP_DP = 0x%02x", state); |
| 2697 | if (state > 0) { | 2698 | |
| 2699 | if (state == it6505->extcon_state || unlikely(state < 0)) | ||
| 2700 | goto unlock; | ||
| 2701 | it6505->extcon_state = state; | ||
| 2702 | if (state) { | ||
| 2698 | DRM_DEV_DEBUG_DRIVER(dev, "start to power on"); | 2703 | DRM_DEV_DEBUG_DRIVER(dev, "start to power on"); |
| 2699 | msleep(100); | 2704 | msleep(100); |
| 2700 | it6505_poweron(it6505); | 2705 | ret = pm_runtime_get_sync(dev); |
| 2706 | |||
| 2707 | /* | ||
| 2708 | * On system resume, extcon_work can be triggered before | ||
| 2709 | * pm_runtime_force_resume re-enables runtime power management. | ||
| 2710 | * Handling the error here to make sure the bridge is powered on. | ||
| 2711 | */ | ||
| 2712 | if (ret) | ||
| 2713 | it6505_poweron(it6505); | ||
| 2701 | } else { | 2714 | } else { |
| 2702 | DRM_DEV_DEBUG_DRIVER(dev, "start to power off"); | 2715 | DRM_DEV_DEBUG_DRIVER(dev, "start to power off"); |
| 2703 | while (it6505_poweroff(it6505) && pwroffretry++ < 5) { | 2716 | pm_runtime_put_sync(dev); |
| 2704 | DRM_DEV_DEBUG_DRIVER(dev, "power off fail %d times", | ||
| 2705 | pwroffretry); | ||
| 2706 | } | ||
| 2707 | 2717 | ||
| 2708 | drm_helper_hpd_irq_event(it6505->bridge.dev); | 2718 | drm_helper_hpd_irq_event(it6505->bridge.dev); |
| 2709 | memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); | 2719 | memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); |
| 2710 | DRM_DEV_DEBUG_DRIVER(dev, "power off it6505 success!"); | 2720 | DRM_DEV_DEBUG_DRIVER(dev, "power off it6505 success!"); |
| 2711 | } | 2721 | } |
| 2712 | 2722 | ||
| 2723 | unlock: | ||
| 2713 | mutex_unlock(&it6505->extcon_lock); | 2724 | mutex_unlock(&it6505->extcon_lock); |
| 2714 | } | 2725 | } |
| 2715 | 2726 | ||
| @@ -2980,6 +2991,28 @@ static void it6505_bridge_atomic_disable(struct drm_bridge *bridge, · 264 unmodified lines | |||
| 2980 | } | 2991 | } |
| 2981 | } | 2992 | } |
| 2982 | 2993 | ||
| 2994 | static void it6505_bridge_atomic_pre_enable(struct drm_bridge *bridge, | ||
| 2995 | struct drm_bridge_state *old_state) | ||
| 2996 | { | ||
| 2997 | struct it6505 *it6505 = bridge_to_it6505(bridge); | ||
| 2998 | struct device *dev = &it6505->client->dev; | ||
| 2999 | |||
| 3000 | DRM_DEV_DEBUG_DRIVER(dev, "start"); | ||
| 3001 | |||
| 3002 | pm_runtime_get_sync(dev); | ||
| 3003 | } | ||
| 3004 | |||
| 3005 | static void it6505_bridge_atomic_post_disable(struct drm_bridge *bridge, | ||
| 3006 | struct drm_bridge_state *old_state) | ||
| 3007 | { | ||
| 3008 | struct it6505 *it6505 = bridge_to_it6505(bridge); | ||
| 3009 | struct device *dev = &it6505->client->dev; | ||
| 3010 | |||
| 3011 | DRM_DEV_DEBUG_DRIVER(dev, "start"); | ||
| 3012 | |||
| 3013 | pm_runtime_put_sync(dev); | ||
| 3014 | } | ||
| 3015 | |||
| 2983 | static enum drm_connector_status | 3016 | static enum drm_connector_status |
| 2984 | it6505_bridge_detect(struct drm_bridge *bridge) | 3017 | it6505_bridge_detect(struct drm_bridge *bridge) |
| 2985 | { | 3018 | { |
| @@ -3014,6 +3047,8 @@ static const struct drm_bridge_funcs it6505_bridge_funcs = { · 28 unmodified lines | |||
| 3014 | .mode_valid = it6505_bridge_mode_valid, | 3047 | .mode_valid = it6505_bridge_mode_valid, |
| 3015 | .atomic_enable = it6505_bridge_atomic_enable, | 3048 | .atomic_enable = it6505_bridge_atomic_enable, |
| 3016 | .atomic_disable = it6505_bridge_atomic_disable, | 3049 | .atomic_disable = it6505_bridge_atomic_disable, |
| 3050 | .atomic_pre_enable = it6505_bridge_atomic_pre_enable, | ||
| 3051 | .atomic_post_disable = it6505_bridge_atomic_post_disable, | ||
| 3017 | .detect = it6505_bridge_detect, | 3052 | .detect = it6505_bridge_detect, |
| 3018 | .get_edid = it6505_bridge_get_edid, | 3053 | .get_edid = it6505_bridge_get_edid, |
| 3019 | }; | 3054 | }; |
| @@ -3032,8 +3067,10 @@ static __maybe_unused int it6505_bridge_suspend(struct device *dev) · 12 unmodified lines | |||
| 3032 | return it6505_poweroff(it6505); | 3067 | return it6505_poweroff(it6505); |
| 3033 | } | 3068 | } |
| 3034 | 3069 | ||
| 3035 | static SIMPLE_DEV_PM_OPS(it6505_bridge_pm_ops, it6505_bridge_suspend, | 3070 | static const struct dev_pm_ops it6505_bridge_pm_ops = { |
| 3036 | it6505_bridge_resume); | 3071 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) |
| 3072 | SET_RUNTIME_PM_OPS(it6505_bridge_suspend, it6505_bridge_resume, NULL) | ||
| 3073 | }; | ||
| 3037 | 3074 | ||
| 3038 | static int it6505_init_pdata(struct it6505 *it6505) | 3075 | static int it6505_init_pdata(struct it6505 *it6505) |
| 3039 | { | 3076 | { |
| @@ -3315,6 +3352,7 @@ static int it6505_i2c_probe(struct i2c_client *client, · 275 unmodified lines | |||
| 3315 | 3352 | ||
| 3316 | DRM_DEV_DEBUG_DRIVER(dev, "it6505 device name: %s", dev_name(dev)); | 3353 | DRM_DEV_DEBUG_DRIVER(dev, "it6505 device name: %s", dev_name(dev)); |
| 3317 | debugfs_init(it6505); | 3354 | debugfs_init(it6505); |
| 3355 | pm_runtime_enable(dev); | ||
| 3318 | 3356 | ||
| 3319 | it6505->bridge.funcs = &it6505_bridge_funcs; | 3357 | it6505->bridge.funcs = &it6505_bridge_funcs; |
| 3320 | it6505->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; | 3358 | it6505->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; |
| @@ -286,7 +286,6 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux, · 285 unmodified lines | |||
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | switch (data & SWAUX_STATUS_MASK) { | 288 | switch (data & SWAUX_STATUS_MASK) { |
| 289 | /* Ignore the DEFER cases as they are already handled in hardware */ | ||
| 290 | case SWAUX_STATUS_NACK: | 289 | case SWAUX_STATUS_NACK: |
| 291 | case SWAUX_STATUS_I2C_NACK: | 290 | case SWAUX_STATUS_I2C_NACK: |
| 292 | /* | 291 | /* |
| @@ -303,6 +302,14 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux, · 10 unmodified lines | |||
| 303 | case SWAUX_STATUS_ACKM: | 302 | case SWAUX_STATUS_ACKM: |
| 304 | len = data & SWAUX_M_MASK; | 303 | len = data & SWAUX_M_MASK; |
| 305 | break; | 304 | break; |
| 305 | case SWAUX_STATUS_DEFER: | ||
| 306 | case SWAUX_STATUS_I2C_DEFER: | ||
| 307 | if (is_native_aux) | ||
| 308 | msg->reply |= DP_AUX_NATIVE_REPLY_DEFER; | ||
| 309 | else | ||
| 310 | msg->reply |= DP_AUX_I2C_REPLY_DEFER; | ||
| 311 | len = data & SWAUX_M_MASK; | ||
| 312 | break; | ||
| 306 | case SWAUX_STATUS_INVALID: | 313 | case SWAUX_STATUS_INVALID: |
| 307 | return -EOPNOTSUPP; | 314 | return -EOPNOTSUPP; |
| 308 | case SWAUX_STATUS_TIMEOUT: | 315 | case SWAUX_STATUS_TIMEOUT: |
| @@ -408,7 +408,7 @@ static void tc_bridge_enable(struct drm_bridge *bridge) · 407 unmodified lines | |||
| 408 | (val >> 8) & 0xFF, val & 0xFF); | 408 | (val >> 8) & 0xFF, val & 0xFF); |
| 409 | 409 | ||
| 410 | d2l_write(tc->i2c, SYSRST, SYS_RST_REG | SYS_RST_DSIRX | SYS_RST_BM | | 410 | d2l_write(tc->i2c, SYSRST, SYS_RST_REG | SYS_RST_DSIRX | SYS_RST_BM | |
| 411 | SYS_RST_LCD | SYS_RST_I2CM | SYS_RST_I2CS); | 411 | SYS_RST_LCD | SYS_RST_I2CM); |
| 412 | usleep_range(30000, 40000); | 412 | usleep_range(30000, 40000); |
| 413 | 413 | ||
| 414 | d2l_write(tc->i2c, PPI_TX_RX_TA, TTA_GET | TTA_SURE); | 414 | d2l_write(tc->i2c, PPI_TX_RX_TA, TTA_GET | TTA_SURE); |
| @@ -3,13 +3,15 @@ · 2 unmodified lines | |||
| 3 | obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o | 3 | obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o |
| 4 | 4 | ||
| 5 | drm_display_helper-y := drm_display_helper_mod.o | 5 | drm_display_helper-y := drm_display_helper_mod.o |
| 6 | drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += drm_dp_dual_mode_helper.o \ | 6 | drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += \ |
| 7 | drm_dp_helper.o \ | 7 | drm_dp_dual_mode_helper.o \ |
| 8 | drm_dp_mst_topology.o \ | 8 | drm_dp_helper.o \ |
| 9 | drm_dsc_helper.o | 9 | drm_dp_mst_topology.o \ |
| 10 | drm_dsc_helper.o | ||
| 10 | drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o | 11 | drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o |
| 11 | drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += drm_hdmi_helper.o \ | 12 | drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \ |
| 12 | drm_scdc_helper.o | 13 | drm_hdmi_helper.o \ |
| 14 | drm_scdc_helper.o | ||
| 13 | drm_display_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o | 15 | drm_display_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o |
| 14 | drm_display_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o | 16 | drm_display_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o |
| 15 | 17 | ||
| @@ -924,59 +924,35 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, · 923 unmodified lines | |||
| 924 | EXPORT_SYMBOL(drm_atomic_helper_check_plane_state); | 924 | EXPORT_SYMBOL(drm_atomic_helper_check_plane_state); |
| 925 | 925 | ||
| 926 | /** | 926 | /** |
| 927 | * drm_atomic_helper_check_crtc_state() - Check CRTC state for validity | 927 | * drm_atomic_helper_check_crtc_primary_plane() - Check CRTC state for primary plane |
| 928 | * @crtc_state: CRTC state to check | 928 | * @crtc_state: CRTC state to check |
| 929 | * @can_disable_primary_planes: can the CRTC be enabled without a primary plane? | ||
| 930 | * | 929 | * |
| 931 | * Checks that a desired CRTC update is valid. Drivers that provide | 930 | * Checks that a CRTC has at least one primary plane attached to it, which is |
| 932 | * their own CRTC handling rather than helper-provided implementations may | 931 | * a requirement on some hardware. Note that this only involves the CRTC side |
| 933 | * still wish to call this function to avoid duplication of error checking | 932 | * of the test. To test if the primary plane is visible or if it can be updated |
| 934 | * code. | 933 | * without the CRTC being enabled, use drm_atomic_helper_check_plane_state() in |
| 935 | * | 934 | * the plane's atomic check. |
| 936 | * Note that @can_disable_primary_planes only tests if the CRTC can be | ||
| 937 | * enabled without a primary plane. To test if a primary plane can be updated | ||
| 938 | * without a CRTC, use drm_atomic_helper_check_plane_state() in the plane's | ||
| 939 | * atomic check. | ||
| 940 | * | 935 | * |
| 941 | * RETURNS: | 936 | * RETURNS: |
| 942 | * Zero if update appears valid, error code on failure | 937 | * 0 if a primary plane is attached to the CRTC, or an error code otherwise |
| 943 | */ | 938 | */ |
| 944 | int drm_atomic_helper_check_crtc_state(struct drm_crtc_state *crtc_state, | 939 | int drm_atomic_helper_check_crtc_primary_plane(struct drm_crtc_state *crtc_state) |
| 945 | bool can_disable_primary_planes) | ||
| 946 | { | 940 | { |
| 947 | struct drm_device *dev = crtc_state->crtc->dev; | 941 | struct drm_crtc *crtc = crtc_state->crtc; |
| 948 | struct drm_atomic_state *state = crtc_state->state; | 942 | struct drm_device *dev = crtc->dev; |
| 949 | 943 | struct drm_plane *plane; | |
| 950 | if (!crtc_state->enable) | ||
| 951 | return 0; | ||
| 952 | 944 | ||
| 953 | /* needs at least one primary plane to be enabled */ | 945 | /* needs at least one primary plane to be enabled */ |
| 954 | if (!can_disable_primary_planes) { | 946 | drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) { |
| 955 | bool has_primary_plane = false; | 947 | if (plane->type == DRM_PLANE_TYPE_PRIMARY) |
| 956 | struct drm_plane *plane; | 948 | return 0; |
| 957 | |||
| 958 | drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) { | ||
| 959 | struct drm_plane_state *plane_state; | ||
| 960 | |||
| 961 | if (plane->type != DRM_PLANE_TYPE_PRIMARY) | ||
| 962 | continue; | ||
| 963 | plane_state = drm_atomic_get_plane_state(state, plane); | ||
| 964 | if (IS_ERR(plane_state)) | ||
| 965 | return PTR_ERR(plane_state); | ||
| 966 | if (plane_state->fb && plane_state->crtc) { | ||
| 967 | has_primary_plane = true; | ||
| 968 | break; | ||
| 969 | } | ||
| 970 | } | ||
| 971 | if (!has_primary_plane) { | ||
| 972 | drm_dbg_kms(dev, "Cannot enable CRTC without a primary plane.\n"); | ||
| 973 | return -EINVAL; | ||
| 974 | } | ||
| 975 | } | 949 | } |
| 976 | 950 | ||
| 977 | return 0; | 951 | drm_dbg_atomic(dev, "[CRTC:%d:%s] primary plane missing\n", crtc->base.id, crtc->name); |
| 952 | |||
| 953 | return -EINVAL; | ||
| 978 | } | 954 | } |
| 979 | EXPORT_SYMBOL(drm_atomic_helper_check_crtc_state); | 955 | EXPORT_SYMBOL(drm_atomic_helper_check_crtc_primary_plane); |
| 980 | 956 | ||
| 981 | /** | 957 | /** |
| 982 | * drm_atomic_helper_check_planes - validate state object for planes changes | 958 | * drm_atomic_helper_check_planes - validate state object for planes changes |
| @@ -464,12 +464,12 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector) · 463 unmodified lines | |||
| 464 | EXPORT_SYMBOL(drm_atomic_helper_connector_reset); | 464 | EXPORT_SYMBOL(drm_atomic_helper_connector_reset); |
| 465 | 465 | ||
| 466 | /** | 466 | /** |
| 467 | * drm_atomic_helper_connector_tv_reset - Resets TV connector properties | 467 | * drm_atomic_helper_connector_tv_margins_reset - Resets TV connector properties |
| 468 | * @connector: DRM connector | 468 | * @connector: DRM connector |
| 469 | * | 469 | * |
| 470 | * Resets the TV-related properties attached to a connector. | 470 | * Resets the TV-related properties attached to a connector. |
| 471 | */ | 471 | */ |
| 472 | void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector) | 472 | void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector) |
| 473 | { | 473 | { |
| 474 | struct drm_cmdline_mode *cmdline = &connector->cmdline_mode; | 474 | struct drm_cmdline_mode *cmdline = &connector->cmdline_mode; |
| 475 | struct drm_connector_state *state = connector->state; | 475 | struct drm_connector_state *state = connector->state; |
| @@ -479,7 +479,7 @@ void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector) · 3 unmodified lines | |||
| 479 | state->tv.margins.top = cmdline->tv_margins.top; | 479 | state->tv.margins.top = cmdline->tv_margins.top; |
| 480 | state->tv.margins.bottom = cmdline->tv_margins.bottom; | 480 | state->tv.margins.bottom = cmdline->tv_margins.bottom; |
| 481 | } | 481 | } |
| 482 | EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset); | 482 | EXPORT_SYMBOL(drm_atomic_helper_connector_tv_margins_reset); |
| 483 | 483 | ||
| 484 | /** | 484 | /** |
| 485 | * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state | 485 | * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state |
| @@ -687,6 +687,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, · 686 unmodified lines | |||
| 687 | */ | 687 | */ |
| 688 | return -EINVAL; | 688 | return -EINVAL; |
| 689 | } else if (property == config->tv_select_subconnector_property) { | 689 | } else if (property == config->tv_select_subconnector_property) { |
| 690 | state->tv.select_subconnector = val; | ||
| 691 | } else if (property == config->tv_subconnector_property) { | ||
| 690 | state->tv.subconnector = val; | 692 | state->tv.subconnector = val; |
| 691 | } else if (property == config->tv_left_margin_property) { | 693 | } else if (property == config->tv_left_margin_property) { |
| 692 | state->tv.margins.left = val; | 694 | state->tv.margins.left = val; |
| @@ -795,6 +797,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector, · 102 unmodified lines | |||
| 795 | else | 797 | else |
| 796 | *val = connector->dpms; | 798 | *val = connector->dpms; |
| 797 | } else if (property == config->tv_select_subconnector_property) { | 799 | } else if (property == config->tv_select_subconnector_property) { |
| 800 | *val = state->tv.select_subconnector; | ||
| 801 | } else if (property == config->tv_subconnector_property) { | ||
| 798 | *val = state->tv.subconnector; | 802 | *val = state->tv.subconnector; |
| 799 | } else if (property == config->tv_left_margin_property) { | 803 | } else if (property == config->tv_left_margin_property) { |
| 800 | *val = state->tv.margins.left; | 804 | *val = state->tv.margins.left; |
| @@ -323,7 +323,7 @@ drm_client_buffer_vmap(struct drm_client_buffer *buffer, · 322 unmodified lines | |||
| 323 | * fd_install step out of the driver backend hooks, to make that | 323 | * fd_install step out of the driver backend hooks, to make that |
| 324 | * final step optional for internal users. | 324 | * final step optional for internal users. |
| 325 | */ | 325 | */ |
| 326 | ret = drm_gem_vmap(buffer->gem, map); | 326 | ret = drm_gem_vmap_unlocked(buffer->gem, map); |
| 327 | if (ret) | 327 | if (ret) |
| 328 | return ret; | 328 | return ret; |
| 329 | 329 | ||
| @@ -345,7 +345,7 @@ void drm_client_buffer_vunmap(struct drm_client_buffer *buffer) · 15 unmodified lines | |||
| 345 | { | 345 | { |
| 346 | struct iosys_map *map = &buffer->map; | 346 | struct iosys_map *map = &buffer->map; |
| 347 | 347 | ||
| 348 | drm_gem_vunmap(buffer->gem, map); | 348 | drm_gem_vunmap_unlocked(buffer->gem, map); |
| 349 | } | 349 | } |
| 350 | EXPORT_SYMBOL(drm_client_buffer_vunmap); | 350 | EXPORT_SYMBOL(drm_client_buffer_vunmap); |
| 351 | 351 | ||
| @@ -434,6 +434,32 @@ done: · 433 unmodified lines | |||
| 434 | } | 434 | } |
| 435 | EXPORT_SYMBOL(drm_crtc_helper_set_mode); | 435 | EXPORT_SYMBOL(drm_crtc_helper_set_mode); |
| 436 | 436 | ||
| 437 | /** | ||
| 438 | * drm_crtc_helper_atomic_check() - Helper to check CRTC atomic-state | ||
| 439 | * @crtc: CRTC to check | ||
| 440 | * @state: atomic state object | ||
| 441 | * | ||
| 442 | * Provides a default CRTC-state check handler for CRTCs that only have | ||
| 443 | * one primary plane attached to it. | ||
| 444 | * | ||
| 445 | * This is often the case for the CRTC of simple framebuffers. See also | ||
| 446 | * drm_plane_helper_atomic_check() for the respective plane-state check | ||
| 447 | * helper function. | ||
| 448 | * | ||
| 449 | * RETURNS: | ||
| 450 | * Zero on success, or an errno code otherwise. | ||
| 451 | */ | ||
| 452 | int drm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) | ||
| 453 | { | ||
| 454 | struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); | ||
| 455 | |||
| 456 | if (!new_crtc_state->enable) | ||
| 457 | return 0; | ||
| 458 | |||
| 459 | return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); | ||
| 460 | } | ||
| 461 | EXPORT_SYMBOL(drm_crtc_helper_atomic_check); | ||
| 462 | |||
| 437 | static void | 463 | static void |
| 438 | drm_crtc_helper_disable(struct drm_crtc *crtc) | 464 | drm_crtc_helper_disable(struct drm_crtc *crtc) |
| 439 | { | 465 | { |
| @@ -1572,15 +1572,6 @@ struct drm_edid { · 1571 unmodified lines | |||
| 1572 | const struct edid *edid; | 1572 | const struct edid *edid; |
| 1573 | }; | 1573 | }; |
| 1574 | 1574 | ||
| 1575 | static bool version_greater(const struct drm_edid *drm_edid, | ||
| 1576 | u8 version, u8 revision) | ||
| 1577 | { | ||
| 1578 | const struct edid *edid = drm_edid->edid; | ||
| 1579 | |||
| 1580 | return edid->version > version || | ||
| 1581 | (edid->version == version && edid->revision > revision); | ||
| 1582 | } | ||
| 1583 | |||
| 1584 | static int edid_hfeeodb_extension_block_count(const struct edid *edid); | 1575 | static int edid_hfeeodb_extension_block_count(const struct edid *edid); |
| 1585 | 1576 | ||
| 1586 | static int edid_hfeeodb_block_count(const struct edid *edid) | 1577 | static int edid_hfeeodb_block_count(const struct edid *edid) |
| @@ -2984,7 +2975,7 @@ is_rb(const struct detailed_timing *descriptor, void *data) · 1397 unmodified lines | |||
| 2984 | BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.cvt.flags) != 15); | 2975 | BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.cvt.flags) != 15); |
| 2985 | 2976 | ||
| 2986 | if (descriptor->data.other_data.data.range.flags == DRM_EDID_CVT_SUPPORT_FLAG && | 2977 | if (descriptor->data.other_data.data.range.flags == DRM_EDID_CVT_SUPPORT_FLAG && |
| 2987 | descriptor->data.other_data.data.range.formula.cvt.flags & 0x10) | 2978 | descriptor->data.other_data.data.range.formula.cvt.flags & DRM_EDID_CVT_FLAGS_REDUCED_BLANKING) |
| 2988 | *res = true; | 2979 | *res = true; |
| 2989 | } | 2980 | } |
| 2990 | 2981 | ||
| @@ -3012,7 +3003,7 @@ find_gtf2(const struct detailed_timing *descriptor, void *data) · 21 unmodified lines | |||
| 3012 | 3003 | ||
| 3013 | BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.flags) != 10); | 3004 | BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.flags) != 10); |
| 3014 | 3005 | ||
| 3015 | if (descriptor->data.other_data.data.range.flags == 0x02) | 3006 | if (descriptor->data.other_data.data.range.flags == DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG) |
| 3016 | *res = descriptor; | 3007 | *res = descriptor; |
| 3017 | } | 3008 | } |
| 3018 | 3009 | ||
| @@ -3077,20 +3068,53 @@ drm_gtf2_2j(const struct drm_edid *drm_edid) · 58 unmodified lines | |||
| 3077 | return descriptor ? descriptor->data.other_data.data.range.formula.gtf2.j : 0; | 3068 | return descriptor ? descriptor->data.other_data.data.range.formula.gtf2.j : 0; |
| 3078 | } | 3069 | } |
| 3079 | 3070 | ||
| 3071 | static void | ||
| 3072 | get_timing_level(const struct detailed_timing *descriptor, void *data) | ||
| 3073 | { | ||
| 3074 | int *res = data; | ||
| 3075 | |||
| 3076 | if (!is_display_descriptor(descriptor, EDID_DETAIL_MONITOR_RANGE)) | ||
| 3077 | return; | ||
| 3078 | |||
| 3079 | BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.flags) != 10); | ||
| 3080 | |||
| 3081 | switch (descriptor->data.other_data.data.range.flags) { | ||
| 3082 | case DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG: | ||
| 3083 | *res = LEVEL_GTF; | ||
| 3084 | break; | ||
| 3085 | case DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG: | ||
| 3086 | *res = LEVEL_GTF2; | ||
| 3087 | break; | ||
| 3088 | case DRM_EDID_CVT_SUPPORT_FLAG: | ||
| 3089 | *res = LEVEL_CVT; | ||
| 3090 | break; | ||
| 3091 | default: | ||
| 3092 | break; | ||
| 3093 | } | ||
| 3094 | } | ||
| 3095 | |||
| 3080 | /* Get standard timing level (CVT/GTF/DMT). */ | 3096 | /* Get standard timing level (CVT/GTF/DMT). */ |
| 3081 | static int standard_timing_level(const struct drm_edid *drm_edid) | 3097 | static int standard_timing_level(const struct drm_edid *drm_edid) |
| 3082 | { | 3098 | { |
| 3083 | const struct edid *edid = drm_edid->edid; | 3099 | const struct edid *edid = drm_edid->edid; |
| 3084 | 3100 | ||
| 3085 | if (edid->revision >= 2) { | 3101 | if (edid->revision >= 4) { |
| 3086 | if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)) | 3102 | /* |
| 3087 | return LEVEL_CVT; | 3103 | * If the range descriptor doesn't |
| 3088 | if (drm_gtf2_hbreak(drm_edid)) | 3104 | * indicate otherwise default to CVT |
| 3089 | return LEVEL_GTF2; | 3105 | */ |
| 3090 | if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) | 3106 | int ret = LEVEL_CVT; |
| 3091 | return LEVEL_GTF; | 3107 | |
| 3108 | drm_for_each_detailed_block(drm_edid, get_timing_level, &ret); | ||
| 3109 | |||
| 3110 | return ret; | ||
| 3111 | } else if (edid->revision >= 3 && drm_gtf2_hbreak(drm_edid)) { | ||
| 3112 | return LEVEL_GTF2; | ||
| 3113 | } else if (edid->revision >= 2) { | ||
| 3114 | return LEVEL_GTF; | ||
| 3115 | } else { | ||
| 3116 | return LEVEL_DMT; | ||
| 3092 | } | 3117 | } |
| 3093 | return LEVEL_DMT; | ||
| 3094 | } | 3118 | } |
| 3095 | 3119 | ||
| 3096 | /* | 3120 | /* |
| @@ -3113,6 +3137,35 @@ static int drm_mode_hsync(const struct drm_display_mode *mode) · 16 unmodified lines | |||
| 3113 | return DIV_ROUND_CLOSEST(mode->clock, mode->htotal); | 3137 | return DIV_ROUND_CLOSEST(mode->clock, mode->htotal); |
| 3114 | } | 3138 | } |
| 3115 | 3139 | ||
| 3140 | static struct drm_display_mode * | ||
| 3141 | drm_gtf2_mode(struct drm_device *dev, | ||
| 3142 | const struct drm_edid *drm_edid, | ||
| 3143 | int hsize, int vsize, int vrefresh_rate) | ||
| 3144 | { | ||
| 3145 | struct drm_display_mode *mode; | ||
| 3146 | |||
| 3147 | /* | ||
| 3148 | * This is potentially wrong if there's ever a monitor with | ||
| 3149 | * more than one ranges section, each claiming a different | ||
| 3150 | * secondary GTF curve. Please don't do that. | ||
| 3151 | */ | ||
| 3152 | mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); | ||
| 3153 | if (!mode) | ||
| 3154 | return NULL; | ||
| 3155 | |||
| 3156 | if (drm_mode_hsync(mode) > drm_gtf2_hbreak(drm_edid)) { | ||
| 3157 | drm_mode_destroy(dev, mode); | ||
| 3158 | mode = drm_gtf_mode_complex(dev, hsize, vsize, | ||
| 3159 | vrefresh_rate, 0, 0, | ||
| 3160 | drm_gtf2_m(drm_edid), | ||
| 3161 | drm_gtf2_2c(drm_edid), | ||
| 3162 | drm_gtf2_k(drm_edid), | ||
| 3163 | drm_gtf2_2j(drm_edid)); | ||
| 3164 | } | ||
| 3165 | |||
| 3166 | return mode; | ||
| 3167 | } | ||
| 3168 | |||
| 3116 | /* | 3169 | /* |
| 3117 | * Take the standard timing params (in this case width, aspect, and refresh) | 3170 | * Take the standard timing params (in this case width, aspect, and refresh) |
| 3118 | * and convert them into a real mode using CVT/GTF/DMT. | 3171 | * and convert them into a real mode using CVT/GTF/DMT. |
| @@ -3201,23 +3254,7 @@ static struct drm_display_mode *drm_mode_std(struct drm_connector *connector, · 82 unmodified lines | |||
| 3201 | mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); | 3254 | mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); |
| 3202 | break; | 3255 | break; |
| 3203 | case LEVEL_GTF2: | 3256 | case LEVEL_GTF2: |
| 3204 | /* | 3257 | mode = drm_gtf2_mode(dev, drm_edid, hsize, vsize, vrefresh_rate); |
| 3205 | * This is potentially wrong if there's ever a monitor with | ||
| 3206 | * more than one ranges section, each claiming a different | ||
| 3207 | * secondary GTF curve. Please don't do that. | ||
| 3208 | */ | ||
| 3209 | mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); | ||
| 3210 | if (!mode) | ||
| 3211 | return NULL; | ||
| 3212 | if (drm_mode_hsync(mode) > drm_gtf2_hbreak(drm_edid)) { | ||
| 3213 | drm_mode_destroy(dev, mode); | ||
| 3214 | mode = drm_gtf_mode_complex(dev, hsize, vsize, | ||
| 3215 | vrefresh_rate, 0, 0, | ||
| 3216 | drm_gtf2_m(drm_edid), | ||
| 3217 | drm_gtf2_2c(drm_edid), | ||
| 3218 | drm_gtf2_k(drm_edid), | ||
| 3219 | drm_gtf2_2j(drm_edid)); | ||
| 3220 | } | ||
| 3221 | break; | 3258 | break; |
| 3222 | case LEVEL_CVT: | 3259 | case LEVEL_CVT: |
| 3223 | mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0, | 3260 | mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0, |
| @@ -3415,7 +3452,7 @@ range_pixel_clock(const struct edid *edid, const u8 *t) · 191 unmodified lines | |||
| 3415 | return 0; | 3452 | return 0; |
| 3416 | 3453 | ||
| 3417 | /* 1.4 with CVT support gives us real precision, yay */ | 3454 | /* 1.4 with CVT support gives us real precision, yay */ |
| 3418 | if (edid->revision >= 4 && t[10] == 0x04) | 3455 | if (edid->revision >= 4 && t[10] == DRM_EDID_CVT_SUPPORT_FLAG) |
| 3419 | return (t[9] * 10000) - ((t[12] >> 2) * 250); | 3456 | return (t[9] * 10000) - ((t[12] >> 2) * 250); |
| 3420 | 3457 | ||
| 3421 | /* 1.3 is pathetic, so fuzz up a bit */ | 3458 | /* 1.3 is pathetic, so fuzz up a bit */ |
| @@ -3441,7 +3478,7 @@ static bool mode_in_range(const struct drm_display_mode *mode, · 19 unmodified lines | |||
| 3441 | return false; | 3478 | return false; |
| 3442 | 3479 | ||
| 3443 | /* 1.4 max horizontal check */ | 3480 | /* 1.4 max horizontal check */ |
| 3444 | if (edid->revision >= 4 && t[10] == 0x04) | 3481 | if (edid->revision >= 4 && t[10] == DRM_EDID_CVT_SUPPORT_FLAG) |
| 3445 | if (t[13] && mode->hdisplay > 8 * (t[13] + (256 * (t[12]&0x3)))) | 3482 | if (t[13] && mode->hdisplay > 8 * (t[13] + (256 * (t[12]&0x3)))) |
| 3446 | return false; | 3483 | return false; |
| 3447 | 3484 | ||
| @@ -3533,6 +3570,35 @@ static int drm_gtf_modes_for_range(struct drm_connector *connector, · 85 unmodified lines | |||
| 3533 | return modes; | 3570 | return modes; |
| 3534 | } | 3571 | } |
| 3535 | 3572 | ||
| 3573 | static int drm_gtf2_modes_for_range(struct drm_connector *connector, | ||
| 3574 | const struct drm_edid *drm_edid, | ||
| 3575 | const struct detailed_timing *timing) | ||
| 3576 | { | ||
| 3577 | int i, modes = 0; | ||
| 3578 | struct drm_display_mode *newmode; | ||
| 3579 | struct drm_device *dev = connector->dev; | ||
| 3580 | |||
| 3581 | for (i = 0; i < ARRAY_SIZE(extra_modes); i++) { | ||
| 3582 | const struct minimode *m = &extra_modes[i]; | ||
| 3583 | |||
| 3584 | newmode = drm_gtf2_mode(dev, drm_edid, m->w, m->h, m->r); | ||
| 3585 | if (!newmode) | ||
| 3586 | return modes; | ||
| 3587 | |||
| 3588 | drm_mode_fixup_1366x768(newmode); | ||
| 3589 | if (!mode_in_range(newmode, drm_edid, timing) || | ||
| 3590 | !valid_inferred_mode(connector, newmode)) { | ||
| 3591 | drm_mode_destroy(dev, newmode); | ||
| 3592 | continue; | ||
| 3593 | } | ||
| 3594 | |||
| 3595 | drm_mode_probed_add(connector, newmode); | ||
| 3596 | modes++; | ||
| 3597 | } | ||
| 3598 | |||
| 3599 | return modes; | ||
| 3600 | } | ||
| 3601 | |||
| 3536 | static int drm_cvt_modes_for_range(struct drm_connector *connector, | 3602 | static int drm_cvt_modes_for_range(struct drm_connector *connector, |
| 3537 | const struct drm_edid *drm_edid, | 3603 | const struct drm_edid *drm_edid, |
| 3538 | const struct detailed_timing *timing) | 3604 | const struct detailed_timing *timing) |
| @@ -3577,25 +3643,29 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) · 38 unmodified lines | |||
| 3577 | closure->drm_edid, | 3643 | closure->drm_edid, |
| 3578 | timing); | 3644 | timing); |
| 3579 | 3645 | ||
| 3580 | if (!version_greater(closure->drm_edid, 1, 1)) | 3646 | if (closure->drm_edid->edid->revision < 2) |
| 3581 | return; /* GTF not defined yet */ | 3647 | return; /* GTF not defined yet */ |
| 3582 | 3648 | ||
| 3583 | switch (range->flags) { | 3649 | switch (range->flags) { |
| 3584 | case 0x02: /* secondary gtf, XXX could do more */ | 3650 | case DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG: |
| 3585 | case 0x00: /* default gtf */ | 3651 | closure->modes += drm_gtf2_modes_for_range(closure->connector, |
| 3652 | closure->drm_edid, | ||
| 3653 | timing); | ||
| 3654 | break; | ||
| 3655 | case DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG: | ||
| 3586 | closure->modes += drm_gtf_modes_for_range(closure->connector, | 3656 | closure->modes += drm_gtf_modes_for_range(closure->connector, |
| 3587 | closure->drm_edid, | 3657 | closure->drm_edid, |
| 3588 | timing); | 3658 | timing); |
| 3589 | break; | 3659 | break; |
| 3590 | case 0x04: /* cvt, only in 1.4+ */ | 3660 | case DRM_EDID_CVT_SUPPORT_FLAG: |
| 3591 | if (!version_greater(closure->drm_edid, 1, 3)) | 3661 | if (closure->drm_edid->edid->revision < 4) |
| 3592 | break; | 3662 | break; |
| 3593 | 3663 | ||
| 3594 | closure->modes += drm_cvt_modes_for_range(closure->connector, | 3664 | closure->modes += drm_cvt_modes_for_range(closure->connector, |
| 3595 | closure->drm_edid, | 3665 | closure->drm_edid, |
| 3596 | timing); | 3666 | timing); |
| 3597 | break; | 3667 | break; |
| 3598 | case 0x01: /* just the ranges, no formula */ | 3668 | case DRM_EDID_RANGE_LIMITS_ONLY_FLAG: |
| 3599 | default: | 3669 | default: |
| 3600 | break; | 3670 | break; |
| 3601 | } | 3671 | } |
| @@ -3609,7 +3679,7 @@ static int add_inferred_modes(struct drm_connector *connector, · 7 unmodified lines | |||
| 3609 | .drm_edid = drm_edid, | 3679 | .drm_edid = drm_edid, |
| 3610 | }; | 3680 | }; |
| 3611 | 3681 | ||
| 3612 | if (version_greater(drm_edid, 1, 0)) | 3682 | if (drm_edid->edid->revision >= 1) |
| 3613 | drm_for_each_detailed_block(drm_edid, do_inferred_modes, &closure); | 3683 | drm_for_each_detailed_block(drm_edid, do_inferred_modes, &closure); |
| 3614 | 3684 | ||
| 3615 | return closure.modes; | 3685 | return closure.modes; |
| @@ -3686,7 +3756,7 @@ static int add_established_modes(struct drm_connector *connector, · 70 unmodified lines | |||
| 3686 | } | 3756 | } |
| 3687 | } | 3757 | } |
| 3688 | 3758 | ||
| 3689 | if (version_greater(drm_edid, 1, 0)) | 3759 | if (edid->revision >= 1) |
| 3690 | drm_for_each_detailed_block(drm_edid, do_established_modes, | 3760 | drm_for_each_detailed_block(drm_edid, do_established_modes, |
| 3691 | &closure); | 3761 | &closure); |
| 3692 | 3762 | ||
| @@ -3741,7 +3811,7 @@ static int add_standard_modes(struct drm_connector *connector, · 48 unmodified lines | |||
| 3741 | } | 3811 | } |
| 3742 | } | 3812 | } |
| 3743 | 3813 | ||
| 3744 | if (version_greater(drm_edid, 1, 0)) | 3814 | if (drm_edid->edid->revision >= 1) |
| 3745 | drm_for_each_detailed_block(drm_edid, do_standard_modes, | 3815 | drm_for_each_detailed_block(drm_edid, do_standard_modes, |
| 3746 | &closure); | 3816 | &closure); |
| 3747 | 3817 | ||
| @@ -3821,7 +3891,7 @@ add_cvt_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) · 73 unmodified lines | |||
| 3821 | .drm_edid = drm_edid, | 3891 | .drm_edid = drm_edid, |
| 3822 | }; | 3892 | }; |
| 3823 | 3893 | ||
| 3824 | if (version_greater(drm_edid, 1, 2)) | 3894 | if (drm_edid->edid->revision >= 3) |
| 3825 | drm_for_each_detailed_block(drm_edid, do_cvt_mode, &closure); | 3895 | drm_for_each_detailed_block(drm_edid, do_cvt_mode, &closure); |
| 3826 | 3896 | ||
| 3827 | /* XXX should also look for CVT codes in VTB blocks */ | 3897 | /* XXX should also look for CVT codes in VTB blocks */ |
| @@ -3873,13 +3943,14 @@ static int add_detailed_modes(struct drm_connector *connector, · 45 unmodified lines | |||
| 3873 | struct detailed_mode_closure closure = { | 3943 | struct detailed_mode_closure closure = { |
| 3874 | .connector = connector, | 3944 | .connector = connector, |
| 3875 | .drm_edid = drm_edid, | 3945 | .drm_edid = drm_edid, |
| 3876 | .preferred = true, | ||
| 3877 | .quirks = quirks, | 3946 | .quirks = quirks, |
| 3878 | }; | 3947 | }; |
| 3879 | 3948 | ||
| 3880 | if (closure.preferred && !version_greater(drm_edid, 1, 3)) | 3949 | if (drm_edid->edid->revision >= 4) |
| 3950 | closure.preferred = true; /* first detailed timing is always preferred */ | ||
| 3951 | else | ||
| 3881 | closure.preferred = | 3952 | closure.preferred = |
| 3882 | (drm_edid->edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); | 3953 | drm_edid->edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING; |
| 3883 | 3954 | ||
| 3884 | drm_for_each_detailed_block(drm_edid, do_detailed_mode, &closure); | 3955 | drm_for_each_detailed_block(drm_edid, do_detailed_mode, &closure); |
| 3885 | 3956 | ||
| @@ -5752,12 +5823,87 @@ static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector, · 1866 unmodified lines | |||
| 5752 | hdmi->y420_dc_modes = dc_mask; | 5823 | hdmi->y420_dc_modes = dc_mask; |
| 5753 | } | 5824 | } |
| 5754 | 5825 | ||
| 5826 | static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc, | ||
| 5827 | const u8 *hf_scds) | ||
| 5828 | { | ||
| 5829 | hdmi_dsc->v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2; | ||
| 5830 | |||
| 5831 | if (!hdmi_dsc->v_1p2) | ||
| 5832 | return; | ||
| 5833 | |||
| 5834 | hdmi_dsc->native_420 = hf_scds[11] & DRM_EDID_DSC_NATIVE_420; | ||
| 5835 | hdmi_dsc->all_bpp = hf_scds[11] & DRM_EDID_DSC_ALL_BPP; | ||
| 5836 | |||
| 5837 | if (hf_scds[11] & DRM_EDID_DSC_16BPC) | ||
| 5838 | hdmi_dsc->bpc_supported = 16; | ||
| 5839 | else if (hf_scds[11] & DRM_EDID_DSC_12BPC) | ||
| 5840 | hdmi_dsc->bpc_supported = 12; | ||
| 5841 | else if (hf_scds[11] & DRM_EDID_DSC_10BPC) | ||
| 5842 | hdmi_dsc->bpc_supported = 10; | ||
| 5843 | else | ||
| 5844 | /* Supports min 8 BPC if DSC 1.2 is supported*/ | ||
| 5845 | hdmi_dsc->bpc_supported = 8; | ||
| 5846 | |||
| 5847 | if (cea_db_payload_len(hf_scds) >= 12 && hf_scds[12]) { | ||
| 5848 | u8 dsc_max_slices; | ||
| 5849 | u8 dsc_max_frl_rate; | ||
| 5850 | |||
| 5851 | dsc_max_frl_rate = (hf_scds[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4; | ||
| 5852 | drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes, | ||
| 5853 | &hdmi_dsc->max_frl_rate_per_lane); | ||
| 5854 | |||
| 5855 | dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES; | ||
| 5856 | |||
| 5857 | switch (dsc_max_slices) { | ||
| 5858 | case 1: | ||
| 5859 | hdmi_dsc->max_slices = 1; | ||
| 5860 | hdmi_dsc->clk_per_slice = 340; | ||
| 5861 | break; | ||
| 5862 | case 2: | ||
| 5863 | hdmi_dsc->max_slices = 2; | ||
| 5864 | hdmi_dsc->clk_per_slice = 340; | ||
| 5865 | break; | ||
| 5866 | case 3: | ||
| 5867 | hdmi_dsc->max_slices = 4; | ||
| 5868 | hdmi_dsc->clk_per_slice = 340; | ||
| 5869 | break; | ||
| 5870 | case 4: | ||
| 5871 | hdmi_dsc->max_slices = 8; | ||
| 5872 | hdmi_dsc->clk_per_slice = 340; | ||
| 5873 | break; | ||
| 5874 | case 5: | ||
| 5875 | hdmi_dsc->max_slices = 8; | ||
| 5876 | hdmi_dsc->clk_per_slice = 400; | ||
| 5877 | break; | ||
| 5878 | case 6: | ||
| 5879 | hdmi_dsc->max_slices = 12; | ||
| 5880 | hdmi_dsc->clk_per_slice = 400; | ||
| 5881 | break; | ||
| 5882 | case 7: | ||
| 5883 | hdmi_dsc->max_slices = 16; | ||
| 5884 | hdmi_dsc->clk_per_slice = 400; | ||
| 5885 | break; | ||
| 5886 | case 0: | ||
| 5887 | default: | ||
| 5888 | hdmi_dsc->max_slices = 0; | ||
| 5889 | hdmi_dsc->clk_per_slice = 0; | ||
| 5890 | } | ||
| 5891 | } | ||
| 5892 | |||
| 5893 | if (cea_db_payload_len(hf_scds) >= 13 && hf_scds[13]) | ||
| 5894 | hdmi_dsc->total_chunk_kbytes = hf_scds[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES; | ||
| 5895 | } | ||
| 5896 | |||
| 5755 | /* Sink Capability Data Structure */ | 5897 | /* Sink Capability Data Structure */ |
| 5756 | static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, | 5898 | static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, |
| 5757 | const u8 *hf_scds) | 5899 | const u8 *hf_scds) |
| 5758 | { | 5900 | { |
| 5759 | struct drm_display_info *display = &connector->display_info; | 5901 | struct drm_display_info *display = &connector->display_info; |
| 5760 | struct drm_hdmi_info *hdmi = &display->hdmi; | 5902 | struct drm_hdmi_info *hdmi = &display->hdmi; |
| 5903 | struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap; | ||
| 5904 | int max_tmds_clock = 0; | ||
| 5905 | u8 max_frl_rate = 0; | ||
| 5906 | bool dsc_support = false; | ||
| 5761 | 5907 | ||
| 5762 | display->has_hdmi_infoframe = true; | 5908 | display->has_hdmi_infoframe = true; |
| 5763 | 5909 | ||
| @@ -5777,14 +5923,13 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, · 13 unmodified lines | |||
| 5777 | */ | 5923 | */ |
| 5778 | 5924 | ||
| 5779 | if (hf_scds[5]) { | 5925 | if (hf_scds[5]) { |
| 5780 | /* max clock is 5000 KHz times block value */ | ||
| 5781 | u32 max_tmds_clock = hf_scds[5] * 5000; | ||
| 5782 | struct drm_scdc *scdc = &hdmi->scdc; | 5926 | struct drm_scdc *scdc = &hdmi->scdc; |
| 5783 | 5927 | ||
| 5928 | /* max clock is 5000 KHz times block value */ | ||
| 5929 | max_tmds_clock = hf_scds[5] * 5000; | ||
| 5930 | |||
| 5784 | if (max_tmds_clock > 340000) { | 5931 | if (max_tmds_clock > 340000) { |
| 5785 | display->max_tmds_clock = max_tmds_clock; | 5932 | display->max_tmds_clock = max_tmds_clock; |
| 5786 | DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n", | ||
| 5787 | display->max_tmds_clock); | ||
| 5788 | } | 5933 | } |
| 5789 | 5934 | ||
| 5790 | if (scdc->supported) { | 5935 | if (scdc->supported) { |
| @@ -5797,74 +5942,21 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, · 6 unmodified lines | |||
| 5797 | } | 5942 | } |
| 5798 | 5943 | ||
| 5799 | if (hf_scds[7]) { | 5944 | if (hf_scds[7]) { |
| 5800 | u8 max_frl_rate; | ||
| 5801 | u8 dsc_max_frl_rate; | ||
| 5802 | u8 dsc_max_slices; | ||
| 5803 | struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap; | ||
| 5804 | |||
| 5805 | DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n"); | ||
| 5806 | max_frl_rate = (hf_scds[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4; | 5945 | max_frl_rate = (hf_scds[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4; |
| 5807 | drm_get_max_frl_rate(max_frl_rate, &hdmi->max_lanes, | 5946 | drm_get_max_frl_rate(max_frl_rate, &hdmi->max_lanes, |
| 5808 | &hdmi->max_frl_rate_per_lane); | 5947 | &hdmi->max_frl_rate_per_lane); |
| 5809 | hdmi_dsc->v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2; | ||
| 5810 | |||
| 5811 | if (hdmi_dsc->v_1p2) { | ||
| 5812 | hdmi_dsc->native_420 = hf_scds[11] & DRM_EDID_DSC_NATIVE_420; | ||
| 5813 | hdmi_dsc->all_bpp = hf_scds[11] & DRM_EDID_DSC_ALL_BPP; | ||
| 5814 | |||
| 5815 | if (hf_scds[11] & DRM_EDID_DSC_16BPC) | ||
| 5816 | hdmi_dsc->bpc_supported = 16; | ||
| 5817 | else if (hf_scds[11] & DRM_EDID_DSC_12BPC) | ||
| 5818 | hdmi_dsc->bpc_supported = 12; | ||
| 5819 | else if (hf_scds[11] & DRM_EDID_DSC_10BPC) | ||
| 5820 | hdmi_dsc->bpc_supported = 10; | ||
| 5821 | else | ||
| 5822 | hdmi_dsc->bpc_supported = 0; | ||
| 5823 | |||
| 5824 | dsc_max_frl_rate = (hf_scds[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4; | ||
| 5825 | drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes, | ||
| 5826 | &hdmi_dsc->max_frl_rate_per_lane); | ||
| 5827 | hdmi_dsc->total_chunk_kbytes = hf_scds[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES; | ||
| 5828 | |||
| 5829 | dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES; | ||
| 5830 | switch (dsc_max_slices) { | ||
| 5831 | case 1: | ||
| 5832 | hdmi_dsc->max_slices = 1; | ||
| 5833 | hdmi_dsc->clk_per_slice = 340; | ||
| 5834 | break; | ||
| 5835 | case 2: | ||
| 5836 | hdmi_dsc->max_slices = 2; | ||
| 5837 | hdmi_dsc->clk_per_slice = 340; | ||
| 5838 | break; | ||
| 5839 | case 3: | ||
| 5840 | hdmi_dsc->max_slices = 4; | ||
| 5841 | hdmi_dsc->clk_per_slice = 340; | ||
| 5842 | break; | ||
| 5843 | case 4: | ||
| 5844 | hdmi_dsc->max_slices = 8; | ||
| 5845 | hdmi_dsc->clk_per_slice = 340; | ||
| 5846 | break; | ||
| 5847 | case 5: | ||
| 5848 | hdmi_dsc->max_slices = 8; | ||
| 5849 | hdmi_dsc->clk_per_slice = 400; | ||
| 5850 | break; | ||
| 5851 | case 6: | ||
| 5852 | hdmi_dsc->max_slices = 12; | ||
| 5853 | hdmi_dsc->clk_per_slice = 400; | ||
| 5854 | break; | ||
| 5855 | case 7: | ||
| 5856 | hdmi_dsc->max_slices = 16; | ||
| 5857 | hdmi_dsc->clk_per_slice = 400; | ||
| 5858 | break; | ||
| 5859 | case 0: | ||
| 5860 | default: | ||
| 5861 | hdmi_dsc->max_slices = 0; | ||
| 5862 | hdmi_dsc->clk_per_slice = 0; | ||
| 5863 | } | ||
| 5864 | } | ||
| 5865 | } | 5948 | } |
| 5866 | 5949 | ||
| 5867 | drm_parse_ycbcr420_deep_color_info(connector, hf_scds); | 5950 | drm_parse_ycbcr420_deep_color_info(connector, hf_scds); |
| 5951 | |||
| 5952 | if (cea_db_payload_len(hf_scds) >= 11 && hf_scds[11]) { | ||
| 5953 | drm_parse_dsc_info(hdmi_dsc, hf_scds); | ||
| 5954 | dsc_support = true; | ||
| 5955 | } | ||
| 5956 | |||
| 5957 | drm_dbg_kms(connector->dev, | ||
| 5958 | "HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n", | ||
| 5959 | max_tmds_clock, str_yes_no(max_frl_rate), str_yes_no(dsc_support)); | ||
| 5868 | } | 5960 | } |
| 5869 | 5961 | ||
| 5870 | static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, | 5962 | static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, |
| @@ -6033,10 +6125,13 @@ void get_monitor_range(const struct detailed_timing *timing, void *c) · 162 unmodified lines | |||
| 6033 | return; | 6125 | return; |
| 6034 | 6126 | ||
| 6035 | /* | 6127 | /* |
| 6036 | * Check for flag range limits only. If flag == 1 then | 6128 | * These limits are used to determine the VRR refresh |
| 6037 | * no additional timing information provided. | 6129 | * rate range. Only the "range limits only" variant |
| 6038 | * Default GTF, GTF Secondary curve and CVT are not | 6130 | * of the range descriptor seems to guarantee that |
| 6039 | * supported | 6131 | * any and all timings are accepted by the sink, as |
| 6132 | * opposed to just timings conforming to the indicated | ||
| 6133 | * formula (GTF/GTF2/CVT). Thus other variants of the | ||
| 6134 | * range descriptor are not accepted here. | ||
| 6040 | */ | 6135 | */ |
| 6041 | if (range->flags != DRM_EDID_RANGE_LIMITS_ONLY_FLAG) | 6136 | if (range->flags != DRM_EDID_RANGE_LIMITS_ONLY_FLAG) |
| 6042 | return; | 6137 | return; |
| @@ -6061,7 +6156,10 @@ static void drm_get_monitor_range(struct drm_connector *connector, · 18 unmodified lines | |||
| 6061 | .drm_edid = drm_edid, | 6156 | .drm_edid = drm_edid, |
| 6062 | }; | 6157 | }; |
| 6063 | 6158 | ||
| 6064 | if (!version_greater(drm_edid, 1, 1)) | 6159 | if (drm_edid->edid->revision < 4) |
| 6160 | return; | ||
| 6161 | |||
| 6162 | if (!(drm_edid->edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ)) | ||
| 6065 | return; | 6163 | return; |
| 6066 | 6164 | ||
| 6067 | drm_for_each_detailed_block(drm_edid, get_monitor_range, &closure); | 6165 | drm_for_each_detailed_block(drm_edid, get_monitor_range, &closure); |
| @@ -6390,7 +6488,7 @@ static int _drm_edid_connector_update(struct drm_connector *connector, · 322 unmodified lines | |||
| 6390 | num_modes += add_cea_modes(connector, drm_edid); | 6488 | num_modes += add_cea_modes(connector, drm_edid); |
| 6391 | num_modes += add_alternate_cea_modes(connector, drm_edid); | 6489 | num_modes += add_alternate_cea_modes(connector, drm_edid); |
| 6392 | num_modes += add_displayid_detailed_modes(connector, drm_edid); | 6490 | num_modes += add_displayid_detailed_modes(connector, drm_edid); |
| 6393 | if (drm_edid->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) | 6491 | if (drm_edid->edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ) |
| 6394 | num_modes += add_inferred_modes(connector, drm_edid); | 6492 | num_modes += add_inferred_modes(connector, drm_edid); |
| 6395 | 6493 | ||
| 6396 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) | 6494 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) |
| @@ -6837,7 +6935,7 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, · 440 unmodified lines | |||
| 6837 | * by non-zero YQ when receiving RGB. There doesn't seem to be any | 6935 | * by non-zero YQ when receiving RGB. There doesn't seem to be any |
| 6838 | * good way to tell which version of CEA-861 the sink supports, so | 6936 | * good way to tell which version of CEA-861 the sink supports, so |
| 6839 | * we limit non-zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based | 6937 | * we limit non-zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based |
| 6840 | * on on CEA-861-F. | 6938 | * on CEA-861-F. |
| 6841 | */ | 6939 | */ |
| 6842 | if (!is_hdmi2_sink(connector) || | 6940 | if (!is_hdmi2_sink(connector) || |
| 6843 | rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) | 6941 | rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) |
| @@ -660,6 +660,11 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d · 659 unmodified lines | |||
| 660 | drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false); | 660 | drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false); |
| 661 | return 0; | 661 | return 0; |
| 662 | } | 662 | } |
| 663 | } else if (dst_format == (DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN)) { | ||
| 664 | if (fb_format == DRM_FORMAT_RGB565) { | ||
| 665 | drm_fb_swab(dst, dst_pitch, src, fb, clip, false); | ||
| 666 | return 0; | ||
| 667 | } | ||
| 663 | } else if (dst_format == DRM_FORMAT_RGB888) { | 668 | } else if (dst_format == DRM_FORMAT_RGB888) { |
| 664 | if (fb_format == DRM_FORMAT_XRGB8888) { | 669 | if (fb_format == DRM_FORMAT_XRGB8888) { |
| 665 | drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip); | 670 | drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip); |
| @@ -678,6 +683,11 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d · 12 unmodified lines | |||
| 678 | drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip); | 683 | drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip); |
| 679 | return 0; | 684 | return 0; |
| 680 | } | 685 | } |
| 686 | } else if (dst_format == DRM_FORMAT_BGRX8888) { | ||
| 687 | if (fb_format == DRM_FORMAT_XRGB8888) { | ||
| 688 | drm_fb_swab(dst, dst_pitch, src, fb, clip, false); | ||
| 689 | return 0; | ||
| 690 | } | ||
| 681 | } | 691 | } |
| 682 | 692 | ||
| 683 | drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n", | 693 | drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n", |
| @@ -1158,6 +1158,8 @@ int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map) · 1157 unmodified lines | |||
| 1158 | { | 1158 | { |
| 1159 | int ret; | 1159 | int ret; |
| 1160 | 1160 | ||
| 1161 | dma_resv_assert_held(obj->resv); | ||
| 1162 | |||
| 1161 | if (!obj->funcs->vmap) | 1163 | if (!obj->funcs->vmap) |
| 1162 | return -EOPNOTSUPP; | 1164 | return -EOPNOTSUPP; |
| 1163 | 1165 | ||
| @@ -1173,6 +1175,8 @@ EXPORT_SYMBOL(drm_gem_vmap); · 9 unmodified lines | |||
| 1173 | 1175 | ||
| 1174 | void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map) | 1176 | void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map) |
| 1175 | { | 1177 | { |
| 1178 | dma_resv_assert_held(obj->resv); | ||
| 1179 | |||
| 1176 | if (iosys_map_is_null(map)) | 1180 | if (iosys_map_is_null(map)) |
| 1177 | return; | 1181 | return; |
| 1178 | 1182 | ||
| @@ -1184,6 +1188,26 @@ void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map) · 5 unmodified lines | |||
| 1184 | } | 1188 | } |
| 1185 | EXPORT_SYMBOL(drm_gem_vunmap); | 1189 | EXPORT_SYMBOL(drm_gem_vunmap); |
| 1186 | 1190 | ||
| 1191 | int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map) | ||
| 1192 | { | ||
| 1193 | int ret; | ||
| 1194 | |||
| 1195 | dma_resv_lock(obj->resv, NULL); | ||
| 1196 | ret = drm_gem_vmap(obj, map); | ||
| 1197 | dma_resv_unlock(obj->resv); | ||
| 1198 | |||
| 1199 | return ret; | ||
| 1200 | } | ||
| 1201 | EXPORT_SYMBOL(drm_gem_vmap_unlocked); | ||
| 1202 | |||
| 1203 | void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map) | ||
| 1204 | { | ||
| 1205 | dma_resv_lock(obj->resv, NULL); | ||
| 1206 | drm_gem_vunmap(obj, map); | ||
| 1207 | dma_resv_unlock(obj->resv); | ||
| 1208 | } | ||
| 1209 | EXPORT_SYMBOL(drm_gem_vunmap_unlocked); | ||
| 1210 | |||
| 1187 | /** | 1211 | /** |
| 1188 | * drm_gem_lock_reservations - Sets up the ww context and acquires | 1212 | * drm_gem_lock_reservations - Sets up the ww context and acquires |
| 1189 | * the lock on an array of GEM objects. | 1213 | * the lock on an array of GEM objects. |
| @@ -230,7 +230,7 @@ void drm_gem_dma_free(struct drm_gem_dma_object *dma_obj) · 229 unmodified lines | |||
| 230 | 230 | ||
| 231 | if (gem_obj->import_attach) { | 231 | if (gem_obj->import_attach) { |
| 232 | if (dma_obj->vaddr) | 232 | if (dma_obj->vaddr) |
| 233 | dma_buf_vunmap(gem_obj->import_attach->dmabuf, &map); | 233 | dma_buf_vunmap_unlocked(gem_obj->import_attach->dmabuf, &map); |
| 234 | drm_prime_gem_destroy(gem_obj, dma_obj->sgt); | 234 | drm_prime_gem_destroy(gem_obj, dma_obj->sgt); |
| 235 | } else if (dma_obj->vaddr) { | 235 | } else if (dma_obj->vaddr) { |
| 236 | if (dma_obj->map_noncoherent) | 236 | if (dma_obj->map_noncoherent) |
| @@ -581,7 +581,7 @@ drm_gem_dma_prime_import_sg_table_vmap(struct drm_device *dev, · 344 unmodified lines | |||
| 581 | struct iosys_map map; | 581 | struct iosys_map map; |
| 582 | int ret; | 582 | int ret; |
| 583 | 583 | ||
| 584 | ret = dma_buf_vmap(attach->dmabuf, &map); | 584 | ret = dma_buf_vmap_unlocked(attach->dmabuf, &map); |
| 585 | if (ret) { | 585 | if (ret) { |
| 586 | DRM_ERROR("Failed to vmap PRIME buffer\n"); | 586 | DRM_ERROR("Failed to vmap PRIME buffer\n"); |
| 587 | return ERR_PTR(ret); | 587 | return ERR_PTR(ret); |
| @@ -589,7 +589,7 @@ drm_gem_dma_prime_import_sg_table_vmap(struct drm_device *dev, · 1 unmodified line | |||
| 589 | 589 | ||
| 590 | obj = drm_gem_dma_prime_import_sg_table(dev, attach, sgt); | 590 | obj = drm_gem_dma_prime_import_sg_table(dev, attach, sgt); |
| 591 | if (IS_ERR(obj)) { | 591 | if (IS_ERR(obj)) { |
| 592 | dma_buf_vunmap(attach->dmabuf, &map); | 592 | dma_buf_vunmap_unlocked(attach->dmabuf, &map); |
| 593 | return obj; | 593 | return obj; |
| 594 | } | 594 | } |
| 595 | 595 | ||
| @@ -354,7 +354,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map, · 353 unmodified lines | |||
| 354 | ret = -EINVAL; | 354 | ret = -EINVAL; |
| 355 | goto err_drm_gem_vunmap; | 355 | goto err_drm_gem_vunmap; |
| 356 | } | 356 | } |
| 357 | ret = drm_gem_vmap(obj, &map[i]); | 357 | ret = drm_gem_vmap_unlocked(obj, &map[i]); |
| 358 | if (ret) | 358 | if (ret) |
| 359 | goto err_drm_gem_vunmap; | 359 | goto err_drm_gem_vunmap; |
| 360 | } | 360 | } |
| @@ -376,7 +376,7 @@ err_drm_gem_vunmap: · 15 unmodified lines | |||
| 376 | obj = drm_gem_fb_get_obj(fb, i); | 376 | obj = drm_gem_fb_get_obj(fb, i); |
| 377 | if (!obj) | 377 | if (!obj) |
| 378 | continue; | 378 | continue; |
| 379 | drm_gem_vunmap(obj, &map[i]); | 379 | drm_gem_vunmap_unlocked(obj, &map[i]); |
| 380 | } | 380 | } |
| 381 | return ret; | 381 | return ret; |
| 382 | } | 382 | } |
| @@ -403,7 +403,7 @@ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map) · 20 unmodified lines | |||
| 403 | continue; | 403 | continue; |
| 404 | if (iosys_map_is_null(&map[i])) | 404 | if (iosys_map_is_null(&map[i])) |
| 405 | continue; | 405 | continue; |
| 406 | drm_gem_vunmap(obj, &map[i]); | 406 | drm_gem_vunmap_unlocked(obj, &map[i]); |
| 407 | } | 407 | } |
| 408 | } | 408 | } |
| 409 | EXPORT_SYMBOL(drm_gem_fb_vunmap); | 409 | EXPORT_SYMBOL(drm_gem_fb_vunmap); |
| @@ -64,13 +64,8 @@ int drm_gem_ttm_vmap(struct drm_gem_object *gem, · 63 unmodified lines | |||
| 64 | struct iosys_map *map) | 64 | struct iosys_map *map) |
| 65 | { | 65 | { |
| 66 | struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem); | 66 | struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem); |
| 67 | int ret; | ||
| 68 | |||
| 69 | dma_resv_lock(gem->resv, NULL); | ||
| 70 | ret = ttm_bo_vmap(bo, map); | ||
| 71 | dma_resv_unlock(gem->resv); | ||
| 72 | 67 | ||
| 73 | return ret; | 68 | return ttm_bo_vmap(bo, map); |
| 74 | } | 69 | } |
| 75 | EXPORT_SYMBOL(drm_gem_ttm_vmap); | 70 | EXPORT_SYMBOL(drm_gem_ttm_vmap); |
| 76 | 71 | ||
| @@ -87,9 +82,7 @@ void drm_gem_ttm_vunmap(struct drm_gem_object *gem, · 10 unmodified lines | |||
| 87 | { | 82 | { |
| 88 | struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem); | 83 | struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem); |
| 89 | 84 | ||
| 90 | dma_resv_lock(gem->resv, NULL); | ||
| 91 | ttm_bo_vunmap(bo, map); | 85 | ttm_bo_vunmap(bo, map); |
| 92 | dma_resv_unlock(gem->resv); | ||
| 93 | } | 86 | } |
| 94 | EXPORT_SYMBOL(drm_gem_ttm_vunmap); | 87 | EXPORT_SYMBOL(drm_gem_ttm_vunmap); |
| 95 | 88 | ||
| @@ -1801,20 +1801,24 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, · 1800 unmodified lines | |||
| 1801 | 1801 | ||
| 1802 | name = mode_option; | 1802 | name = mode_option; |
| 1803 | 1803 | ||
| 1804 | /* Locate the start of named options */ | ||
| 1805 | options_ptr = strchr(name, ','); | ||
| 1806 | if (options_ptr) | ||
| 1807 | options_off = options_ptr - name; | ||
| 1808 | else | ||
| 1809 | options_off = strlen(name); | ||
| 1810 | |||
| 1804 | /* Try to locate the bpp and refresh specifiers, if any */ | 1811 | /* Try to locate the bpp and refresh specifiers, if any */ |
| 1805 | bpp_ptr = strchr(name, '-'); | 1812 | bpp_ptr = strnchr(name, options_off, '-'); |
| 1813 | while (bpp_ptr && !isdigit(bpp_ptr[1])) | ||
| 1814 | bpp_ptr = strnchr(bpp_ptr + 1, options_off, '-'); | ||
| 1806 | if (bpp_ptr) | 1815 | if (bpp_ptr) |
| 1807 | bpp_off = bpp_ptr - name; | 1816 | bpp_off = bpp_ptr - name; |
| 1808 | 1817 | ||
| 1809 | refresh_ptr = strchr(name, '@'); | 1818 | refresh_ptr = strnchr(name, options_off, '@'); |
| 1810 | if (refresh_ptr) | 1819 | if (refresh_ptr) |
| 1811 | refresh_off = refresh_ptr - name; | 1820 | refresh_off = refresh_ptr - name; |
| 1812 | 1821 | ||
| 1813 | /* Locate the start of named options */ | ||
| 1814 | options_ptr = strchr(name, ','); | ||
| 1815 | if (options_ptr) | ||
| 1816 | options_off = options_ptr - name; | ||
| 1817 | |||
| 1818 | /* Locate the end of the name / resolution, and parse it */ | 1822 | /* Locate the end of the name / resolution, and parse it */ |
| 1819 | if (bpp_ptr) { | 1823 | if (bpp_ptr) { |
| 1820 | mode_end = bpp_off; | 1824 | mode_end = bpp_off; |
| @@ -298,7 +298,9 @@ EXPORT_SYMBOL(drm_plane_helper_destroy); · 297 unmodified lines | |||
| 298 | * scale and positioning are not expected to change since the plane is always | 298 | * scale and positioning are not expected to change since the plane is always |
| 299 | * a fullscreen scanout buffer. | 299 | * a fullscreen scanout buffer. |
| 300 | * | 300 | * |
| 301 | * This is often the case for the primary plane of simple framebuffers. | 301 | * This is often the case for the primary plane of simple framebuffers. See |
| 302 | * also drm_crtc_helper_atomic_check() for the respective CRTC-state check | ||
| 303 | * helper function. | ||
| 302 | * | 304 | * |
| 303 | * RETURNS: | 305 | * RETURNS: |
| 304 | * Zero on success, or an errno code otherwise. | 306 | * Zero on success, or an errno code otherwise. |
| @@ -940,7 +940,7 @@ struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, · 939 unmodified lines | |||
| 940 | 940 | ||
| 941 | get_dma_buf(dma_buf); | 941 | get_dma_buf(dma_buf); |
| 942 | 942 | ||
| 943 | sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); | 943 | sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL); |
| 944 | if (IS_ERR(sgt)) { | 944 | if (IS_ERR(sgt)) { |
| 945 | ret = PTR_ERR(sgt); | 945 | ret = PTR_ERR(sgt); |
| 946 | goto fail_detach; | 946 | goto fail_detach; |
| @@ -958,7 +958,7 @@ struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, · 11 unmodified lines | |||
| 958 | return obj; | 958 | return obj; |
| 959 | 959 | ||
| 960 | fail_unmap: | 960 | fail_unmap: |
| 961 | dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); | 961 | dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL); |
| 962 | fail_detach: | 962 | fail_detach: |
| 963 | dma_buf_detach(dma_buf, attach); | 963 | dma_buf_detach(dma_buf, attach); |
| 964 | dma_buf_put(dma_buf); | 964 | dma_buf_put(dma_buf); |
| @@ -1056,7 +1056,7 @@ void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg) · 91 unmodified lines | |||
| 1056 | 1056 | ||
| 1057 | attach = obj->import_attach; | 1057 | attach = obj->import_attach; |
| 1058 | if (sg) | 1058 | if (sg) |
| 1059 | dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL); | 1059 | dma_buf_unmap_attachment_unlocked(attach, sg, DMA_BIDIRECTIONAL); |
| 1060 | dma_buf = attach->dmabuf; | 1060 | dma_buf = attach->dmabuf; |
| 1061 | dma_buf_detach(attach->dmabuf, attach); | 1061 | dma_buf_detach(attach->dmabuf, attach); |
| 1062 | /* remove the reference */ | 1062 | /* remove the reference */ |
| @@ -102,10 +102,14 @@ static int drm_simple_kms_crtc_check(struct drm_crtc *crtc, · 101 unmodified lines | |||
| 102 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); | 102 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); |
| 103 | int ret; | 103 | int ret; |
| 104 | 104 | ||
| 105 | ret = drm_atomic_helper_check_crtc_state(crtc_state, false); | 105 | if (!crtc_state->enable) |
| 106 | goto out; | ||
| 107 | |||
| 108 | ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); | ||
| 106 | if (ret) | 109 | if (ret) |
| 107 | return ret; | 110 | return ret; |
| 108 | 111 | ||
| 112 | out: | ||
| 109 | return drm_atomic_add_affected_planes(state, crtc); | 113 | return drm_atomic_add_affected_planes(state, crtc); |
| 110 | } | 114 | } |
| 111 | 115 | ||
| @@ -65,7 +65,7 @@ static void etnaviv_gem_prime_release(struct etnaviv_gem_object *etnaviv_obj) · 64 unmodified lines | |||
| 65 | struct iosys_map map = IOSYS_MAP_INIT_VADDR(etnaviv_obj->vaddr); | 65 | struct iosys_map map = IOSYS_MAP_INIT_VADDR(etnaviv_obj->vaddr); |
| 66 | 66 | ||
| 67 | if (etnaviv_obj->vaddr) | 67 | if (etnaviv_obj->vaddr) |
| 68 | dma_buf_vunmap(etnaviv_obj->base.import_attach->dmabuf, &map); | 68 | dma_buf_vunmap_unlocked(etnaviv_obj->base.import_attach->dmabuf, &map); |
| 69 | 69 | ||
| 70 | /* Don't drop the pages for imported dmabuf, as they are not | 70 | /* Don't drop the pages for imported dmabuf, as they are not |
| 71 | * ours, just free the array we allocated: | 71 | * ours, just free the array we allocated: |
| @@ -286,7 +286,7 @@ static int psbfb_create(struct drm_fb_helper *fb_helper, · 285 unmodified lines | |||
| 286 | 286 | ||
| 287 | info->fbops = &psbfb_unaccel_ops; | 287 | info->fbops = &psbfb_unaccel_ops; |
| 288 | 288 | ||
| 289 | info->fix.smem_start = dev->mode_config.fb_base; | 289 | info->fix.smem_start = dev_priv->fb_base; |
| 290 | info->fix.smem_len = size; | 290 | info->fix.smem_len = size; |
| 291 | info->fix.ywrapstep = 0; | 291 | info->fix.ywrapstep = 0; |
| 292 | info->fix.ypanstep = 0; | 292 | info->fix.ypanstep = 0; |
| @@ -296,7 +296,7 @@ static int psbfb_create(struct drm_fb_helper *fb_helper, · 3 unmodified lines | |||
| 296 | info->screen_size = size; | 296 | info->screen_size = size; |
| 297 | 297 | ||
| 298 | if (dev_priv->gtt.stolen_size) { | 298 | if (dev_priv->gtt.stolen_size) { |
| 299 | info->apertures->ranges[0].base = dev->mode_config.fb_base; | 299 | info->apertures->ranges[0].base = dev_priv->fb_base; |
| 300 | info->apertures->ranges[0].size = dev_priv->gtt.stolen_size; | 300 | info->apertures->ranges[0].size = dev_priv->gtt.stolen_size; |
| 301 | } | 301 | } |
| 302 | 302 | ||
| @@ -527,7 +527,7 @@ void psb_modeset_init(struct drm_device *dev) · 224 unmodified lines | |||
| 527 | 527 | ||
| 528 | /* set memory base */ | 528 | /* set memory base */ |
| 529 | /* Oaktrail and Poulsbo should use BAR 2*/ | 529 | /* Oaktrail and Poulsbo should use BAR 2*/ |
| 530 | pci_read_config_dword(pdev, PSB_BSM, (u32 *)&(dev->mode_config.fb_base)); | 530 | pci_read_config_dword(pdev, PSB_BSM, (u32 *)&(dev_priv->fb_base)); |
| 531 | 531 | ||
| 532 | /* num pipes is 2 for PSB but 1 for Mrst */ | 532 | /* num pipes is 2 for PSB but 1 for Mrst */ |
| 533 | for (i = 0; i < dev_priv->num_pipe; i++) | 533 | for (i = 0; i < dev_priv->num_pipe; i++) |
| @@ -523,6 +523,7 @@ struct drm_psb_private { · 522 unmodified lines | |||
| 523 | uint32_t blc_adj2; | 523 | uint32_t blc_adj2; |
| 524 | 524 | ||
| 525 | struct drm_fb_helper *fb_helper; | 525 | struct drm_fb_helper *fb_helper; |
| 526 | resource_size_t fb_base; | ||
| 526 | 527 | ||
| 527 | bool dsr_enable; | 528 | bool dsr_enable; |
| 528 | u32 dsr_fb_update; | 529 | u32 dsr_fb_update; |
| @@ -355,7 +355,7 @@ static void gud_connector_reset(struct drm_connector *connector) · 354 unmodified lines | |||
| 355 | drm_atomic_helper_connector_reset(connector); | 355 | drm_atomic_helper_connector_reset(connector); |
| 356 | connector->state->tv = gconn->initial_tv_state; | 356 | connector->state->tv = gconn->initial_tv_state; |
| 357 | /* Set margins from command line */ | 357 | /* Set margins from command line */ |
| 358 | drm_atomic_helper_connector_tv_reset(connector); | 358 | drm_atomic_helper_connector_tv_margins_reset(connector); |
| 359 | if (gconn->initial_brightness >= 0) | 359 | if (gconn->initial_brightness >= 0) |
| 360 | connector->state->tv.brightness = gconn->initial_brightness; | 360 | connector->state->tv.brightness = gconn->initial_brightness; |
| 361 | } | 361 | } |
| @@ -105,7 +105,6 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv) · 104 unmodified lines | |||
| 105 | dev->mode_config.max_width = 1920; | 105 | dev->mode_config.max_width = 1920; |
| 106 | dev->mode_config.max_height = 1200; | 106 | dev->mode_config.max_height = 1200; |
| 107 | 107 | ||
| 108 | dev->mode_config.fb_base = priv->fb_base; | ||
| 109 | dev->mode_config.preferred_depth = 32; | 108 | dev->mode_config.preferred_depth = 32; |
| 110 | dev->mode_config.prefer_shadow = 1; | 109 | dev->mode_config.prefer_shadow = 1; |
| 111 | 110 | ||
| @@ -212,7 +211,7 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv) · 100 unmodified lines | |||
| 212 | { | 211 | { |
| 213 | struct drm_device *dev = &priv->dev; | 212 | struct drm_device *dev = &priv->dev; |
| 214 | struct pci_dev *pdev = to_pci_dev(dev->dev); | 213 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
| 215 | resource_size_t addr, size, ioaddr, iosize; | 214 | resource_size_t ioaddr, iosize; |
| 216 | 215 | ||
| 217 | ioaddr = pci_resource_start(pdev, 1); | 216 | ioaddr = pci_resource_start(pdev, 1); |
| 218 | iosize = pci_resource_len(pdev, 1); | 217 | iosize = pci_resource_len(pdev, 1); |
| @@ -222,16 +221,6 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv) · 3 unmodified lines | |||
| 222 | return -ENOMEM; | 221 | return -ENOMEM; |
| 223 | } | 222 | } |
| 224 | 223 | ||
| 225 | addr = pci_resource_start(pdev, 0); | ||
| 226 | size = pci_resource_len(pdev, 0); | ||
| 227 | priv->fb_map = devm_ioremap(dev->dev, addr, size); | ||
| 228 | if (!priv->fb_map) { | ||
| 229 | drm_err(dev, "Cannot map framebuffer\n"); | ||
| 230 | return -ENOMEM; | ||
| 231 | } | ||
| 232 | priv->fb_base = addr; | ||
| 233 | priv->fb_size = size; | ||
| 234 | |||
| 235 | return 0; | 224 | return 0; |
| 236 | } | 225 | } |
| 237 | 226 | ||
| @@ -271,7 +260,8 @@ static int hibmc_load(struct drm_device *dev) · 33 unmodified lines | |||
| 271 | if (ret) | 260 | if (ret) |
| 272 | goto err; | 261 | goto err; |
| 273 | 262 | ||
| 274 | ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0), priv->fb_size); | 263 | ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0), |
| 264 | pci_resource_len(pdev, 0)); | ||
| 275 | if (ret) { | 265 | if (ret) { |
| 276 | drm_err(dev, "Error initializing VRAM MM; %d\n", ret); | 266 | drm_err(dev, "Error initializing VRAM MM; %d\n", ret); |
| 277 | goto err; | 267 | goto err; |
| @@ -32,9 +32,6 @@ struct hibmc_connector { · 31 unmodified lines | |||
| 32 | struct hibmc_drm_private { | 32 | struct hibmc_drm_private { |
| 33 | /* hw */ | 33 | /* hw */ |
| 34 | void __iomem *mmio; | 34 | void __iomem *mmio; |
| 35 | void __iomem *fb_map; | ||
| 36 | resource_size_t fb_base; | ||
| 37 | resource_size_t fb_size; | ||
| 38 | 35 | ||
| 39 | /* drm */ | 36 | /* drm */ |
| 40 | struct drm_device dev; | 37 | struct drm_device dev; |
| @@ -72,7 +72,7 @@ static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf, · 71 unmodified lines | |||
| 72 | struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); | 72 | struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); |
| 73 | void *vaddr; | 73 | void *vaddr; |
| 74 | 74 | ||
| 75 | vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | 75 | vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); |
| 76 | if (IS_ERR(vaddr)) | 76 | if (IS_ERR(vaddr)) |
| 77 | return PTR_ERR(vaddr); | 77 | return PTR_ERR(vaddr); |
| 78 | 78 | ||
| @@ -290,7 +290,21 @@ void __i915_gem_object_pages_fini(struct drm_i915_gem_object *obj) · 289 unmodified lines | |||
| 290 | __i915_gem_object_free_mmaps(obj); | 290 | __i915_gem_object_free_mmaps(obj); |
| 291 | 291 | ||
| 292 | atomic_set(&obj->mm.pages_pin_count, 0); | 292 | atomic_set(&obj->mm.pages_pin_count, 0); |
| 293 | |||
| 294 | /* | ||
| 295 | * dma_buf_unmap_attachment() requires reservation to be | ||
| 296 | * locked. The imported GEM shouldn't share reservation lock | ||
| 297 | * and ttm_bo_cleanup_memtype_use() shouldn't be invoked for | ||
| 298 | * dma-buf, so it's safe to take the lock. | ||
| 299 | */ | ||
| 300 | if (obj->base.import_attach) | ||
| 301 | i915_gem_object_lock(obj, NULL); | ||
| 302 | |||
| 293 | __i915_gem_object_put_pages(obj); | 303 | __i915_gem_object_put_pages(obj); |
| 304 | |||
| 305 | if (obj->base.import_attach) | ||
| 306 | i915_gem_object_unlock(obj); | ||
| 307 | |||
| 294 | GEM_BUG_ON(i915_gem_object_has_pages(obj)); | 308 | GEM_BUG_ON(i915_gem_object_has_pages(obj)); |
| 295 | } | 309 | } |
| 296 | 310 | ||
| @@ -213,7 +213,7 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915, · 212 unmodified lines | |||
| 213 | goto out_import; | 213 | goto out_import; |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | st = dma_buf_map_attachment(import_attach, DMA_BIDIRECTIONAL); | 216 | st = dma_buf_map_attachment_unlocked(import_attach, DMA_BIDIRECTIONAL); |
| 217 | if (IS_ERR(st)) { | 217 | if (IS_ERR(st)) { |
| 218 | err = PTR_ERR(st); | 218 | err = PTR_ERR(st); |
| 219 | goto out_detach; | 219 | goto out_detach; |
| @@ -226,7 +226,7 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915, · 6 unmodified lines | |||
| 226 | timeout = -ETIME; | 226 | timeout = -ETIME; |
| 227 | } | 227 | } |
| 228 | err = timeout > 0 ? 0 : timeout; | 228 | err = timeout > 0 ? 0 : timeout; |
| 229 | dma_buf_unmap_attachment(import_attach, st, DMA_BIDIRECTIONAL); | 229 | dma_buf_unmap_attachment_unlocked(import_attach, st, DMA_BIDIRECTIONAL); |
| 230 | out_detach: | 230 | out_detach: |
| 231 | dma_buf_detach(dmabuf, import_attach); | 231 | dma_buf_detach(dmabuf, import_attach); |
| 232 | out_import: | 232 | out_import: |
| @@ -296,7 +296,7 @@ static int igt_dmabuf_import(void *arg) · 63 unmodified lines | |||
| 296 | goto out_obj; | 296 | goto out_obj; |
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | err = dma_buf_vmap(dmabuf, &map); | 299 | err = dma_buf_vmap_unlocked(dmabuf, &map); |
| 300 | dma_map = err ? NULL : map.vaddr; | 300 | dma_map = err ? NULL : map.vaddr; |
| 301 | if (!dma_map) { | 301 | if (!dma_map) { |
| 302 | pr_err("dma_buf_vmap failed\n"); | 302 | pr_err("dma_buf_vmap failed\n"); |
| @@ -337,7 +337,7 @@ static int igt_dmabuf_import(void *arg) · 34 unmodified lines | |||
| 337 | 337 | ||
| 338 | err = 0; | 338 | err = 0; |
| 339 | out_dma_map: | 339 | out_dma_map: |
| 340 | dma_buf_vunmap(dmabuf, &map); | 340 | dma_buf_vunmap_unlocked(dmabuf, &map); |
| 341 | out_obj: | 341 | out_obj: |
| 342 | i915_gem_object_put(obj); | 342 | i915_gem_object_put(obj); |
| 343 | out_dmabuf: | 343 | out_dmabuf: |
| @@ -358,7 +358,7 @@ static int igt_dmabuf_import_ownership(void *arg) · 14 unmodified lines | |||
| 358 | if (IS_ERR(dmabuf)) | 358 | if (IS_ERR(dmabuf)) |
| 359 | return PTR_ERR(dmabuf); | 359 | return PTR_ERR(dmabuf); |
| 360 | 360 | ||
| 361 | err = dma_buf_vmap(dmabuf, &map); | 361 | err = dma_buf_vmap_unlocked(dmabuf, &map); |
| 362 | ptr = err ? NULL : map.vaddr; | 362 | ptr = err ? NULL : map.vaddr; |
| 363 | if (!ptr) { | 363 | if (!ptr) { |
| 364 | pr_err("dma_buf_vmap failed\n"); | 364 | pr_err("dma_buf_vmap failed\n"); |
| @@ -367,7 +367,7 @@ static int igt_dmabuf_import_ownership(void *arg) · 2 unmodified lines | |||
| 367 | } | 367 | } |
| 368 | 368 | ||
| 369 | memset(ptr, 0xc5, PAGE_SIZE); | 369 | memset(ptr, 0xc5, PAGE_SIZE); |
| 370 | dma_buf_vunmap(dmabuf, &map); | 370 | dma_buf_vunmap_unlocked(dmabuf, &map); |
| 371 | 371 | ||
| 372 | obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf)); | 372 | obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf)); |
| 373 | if (IS_ERR(obj)) { | 373 | if (IS_ERR(obj)) { |
| @@ -418,7 +418,7 @@ static int igt_dmabuf_export_vmap(void *arg) · 44 unmodified lines | |||
| 418 | } | 418 | } |
| 419 | i915_gem_object_put(obj); | 419 | i915_gem_object_put(obj); |
| 420 | 420 | ||
| 421 | err = dma_buf_vmap(dmabuf, &map); | 421 | err = dma_buf_vmap_unlocked(dmabuf, &map); |
| 422 | ptr = err ? NULL : map.vaddr; | 422 | ptr = err ? NULL : map.vaddr; |
| 423 | if (!ptr) { | 423 | if (!ptr) { |
| 424 | pr_err("dma_buf_vmap failed\n"); | 424 | pr_err("dma_buf_vmap failed\n"); |
| @@ -435,7 +435,7 @@ static int igt_dmabuf_export_vmap(void *arg) · 10 unmodified lines | |||
| 435 | memset(ptr, 0xc5, dmabuf->size); | 435 | memset(ptr, 0xc5, dmabuf->size); |
| 436 | 436 | ||
| 437 | err = 0; | 437 | err = 0; |
| 438 | dma_buf_vunmap(dmabuf, &map); | 438 | dma_buf_vunmap_unlocked(dmabuf, &map); |
| 439 | out: | 439 | out: |
| 440 | dma_buf_put(dmabuf); | 440 | dma_buf_put(dmabuf); |
| 441 | return err; | 441 | return err; |
| @@ -371,7 +371,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task) · 370 unmodified lines | |||
| 371 | } else { | 371 | } else { |
| 372 | buffer_chunk->size = lima_bo_size(bo); | 372 | buffer_chunk->size = lima_bo_size(bo); |
| 373 | 373 | ||
| 374 | ret = drm_gem_shmem_vmap(&bo->base, &map); | 374 | ret = drm_gem_vmap_unlocked(&bo->base.base, &map); |
| 375 | if (ret) { | 375 | if (ret) { |
| 376 | kvfree(et); | 376 | kvfree(et); |
| 377 | goto out; | 377 | goto out; |
| @@ -379,7 +379,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task) · 1 unmodified line | |||
| 379 | 379 | ||
| 380 | memcpy(buffer_chunk + 1, map.vaddr, buffer_chunk->size); | 380 | memcpy(buffer_chunk + 1, map.vaddr, buffer_chunk->size); |
| 381 | 381 | ||
| 382 | drm_gem_shmem_vunmap(&bo->base, &map); | 382 | drm_gem_vunmap_unlocked(&bo->base.base, &map); |
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | buffer_chunk = (void *)(buffer_chunk + 1) + buffer_chunk->size; | 385 | buffer_chunk = (void *)(buffer_chunk + 1) + buffer_chunk->size; |
| @@ -284,7 +284,8 @@ static void mgag200_g200se_04_pixpllc_atomic_update(struct drm_crtc *crtc, · 283 unmodified lines | |||
| 284 | pixpllcp = pixpllc->p - 1; | 284 | pixpllcp = pixpllc->p - 1; |
| 285 | pixpllcs = pixpllc->s; | 285 | pixpllcs = pixpllc->s; |
| 286 | 286 | ||
| 287 | xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1); | 287 | // For G200SE A, BIT(7) should be set unconditionally. |
| 288 | xpixpllcm = BIT(7) | pixpllcm; | ||
| 288 | xpixpllcn = pixpllcn; | 289 | xpixpllcn = pixpllcn; |
| 289 | xpixpllcp = (pixpllcs << 3) | pixpllcp; | 290 | xpixpllcp = (pixpllcs << 3) | pixpllcp; |
| 290 | 291 | ||
| @@ -579,13 +579,13 @@ int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_st · 578 unmodified lines | |||
| 579 | struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut; | 579 | struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut; |
| 580 | int ret; | 580 | int ret; |
| 581 | 581 | ||
| 582 | ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); | ||
| 583 | if (ret) | ||
| 584 | return ret; | ||
| 585 | |||
| 586 | if (!new_crtc_state->enable) | 582 | if (!new_crtc_state->enable) |
| 587 | return 0; | 583 | return 0; |
| 588 | 584 | ||
| 585 | ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); | ||
| 586 | if (ret) | ||
| 587 | return ret; | ||
| 588 | |||
| 589 | if (new_crtc_state->mode_changed) { | 589 | if (new_crtc_state->mode_changed) { |
| 590 | if (funcs->pixpllc_atomic_check) { | 590 | if (funcs->pixpllc_atomic_check) { |
| 591 | ret = funcs->pixpllc_atomic_check(crtc, new_state); | 591 | ret = funcs->pixpllc_atomic_check(crtc, new_state); |
| @@ -601,7 +601,7 @@ int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_st · 9 unmodified lines | |||
| 601 | } | 601 | } |
| 602 | } | 602 | } |
| 603 | 603 | ||
| 604 | return drm_atomic_add_affected_planes(new_state, crtc); | 604 | return 0; |
| 605 | } | 605 | } |
| 606 | 606 | ||
| 607 | void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state) | 607 | void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state) |
| @@ -824,7 +824,6 @@ int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_avail · 216 unmodified lines | |||
| 824 | dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH; | 824 | dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH; |
| 825 | dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; | 825 | dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; |
| 826 | dev->mode_config.preferred_depth = 24; | 826 | dev->mode_config.preferred_depth = 24; |
| 827 | dev->mode_config.fb_base = mdev->vram_res->start; | ||
| 828 | dev->mode_config.funcs = &mgag200_mode_config_funcs; | 827 | dev->mode_config.funcs = &mgag200_mode_config_funcs; |
| 829 | dev->mode_config.helper_private = &mgag200_mode_config_helper_funcs; | 828 | dev->mode_config.helper_private = &mgag200_mode_config_helper_funcs; |
| 830 | 829 | ||
| @@ -109,8 +109,6 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, · 108 unmodified lines | |||
| 109 | 109 | ||
| 110 | drm_fb_helper_fill_info(fbi, helper, sizes); | 110 | drm_fb_helper_fill_info(fbi, helper, sizes); |
| 111 | 111 | ||
| 112 | dev->mode_config.fb_base = paddr; | ||
| 113 | |||
| 114 | fbi->screen_base = msm_gem_get_vaddr(bo); | 112 | fbi->screen_base = msm_gem_get_vaddr(bo); |
| 115 | if (IS_ERR(fbi->screen_base)) { | 113 | if (IS_ERR(fbi->screen_base)) { |
| 116 | ret = PTR_ERR(fbi->screen_base); | 114 | ret = PTR_ERR(fbi->screen_base); |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | |||
| 15 | #include <drm/drm_atomic.h> | 15 | #include <drm/drm_atomic.h> |
| 16 | #include <drm/drm_atomic_helper.h> | 16 | #include <drm/drm_atomic_helper.h> |
| 17 | #include <drm/drm_bridge.h> | 17 | #include <drm/drm_bridge.h> |
| 18 | #include <drm/drm_color_mgmt.h> | ||
| 18 | #include <drm/drm_crtc.h> | 19 | #include <drm/drm_crtc.h> |
| 19 | #include <drm/drm_encoder.h> | 20 | #include <drm/drm_encoder.h> |
| 20 | #include <drm/drm_fb_dma_helper.h> | 21 | #include <drm/drm_fb_dma_helper.h> |
| @@ -31,13 +32,126 @@ · 10 unmodified lines | |||
| 31 | /* ----------------------------------------------------------------------------- | 32 | /* ----------------------------------------------------------------------------- |
| 32 | * CRTC | 33 | * CRTC |
| 33 | */ | 34 | */ |
| 35 | |||
| 36 | /* | ||
| 37 | * For conversion from YCbCr to RGB, the CSC operates as follows: | ||
| 38 | * | ||
| 39 | * |R| |A1 A2 A3| |Y + D1| | ||
| 40 | * |G| = |B1 B2 B3| * |Cb + D2| | ||
| 41 | * |B| |C1 C2 C3| |Cr + D3| | ||
| 42 | * | ||
| 43 | * The A, B and C coefficients are expressed as Q2.8 fixed point values, and | ||
| 44 | * the D coefficients as Q0.8. Despite the reference manual stating the | ||
| 45 | * opposite, the D1, D2 and D3 offset values are added to Y, Cb and Cr, not | ||
| 46 | * subtracted. They must thus be programmed with negative values. | ||
| 47 | */ | ||
| 48 | static const u32 lcdif_yuv2rgb_coeffs[3][2][6] = { | ||
| 49 | [DRM_COLOR_YCBCR_BT601] = { | ||
| 50 | [DRM_COLOR_YCBCR_LIMITED_RANGE] = { | ||
| 51 | /* | ||
| 52 | * BT.601 limited range: | ||
| 53 | * | ||
| 54 | * |R| |1.1644 0.0000 1.5960| |Y - 16 | | ||
| 55 | * |G| = |1.1644 -0.3917 -0.8129| * |Cb - 128| | ||
| 56 | * |B| |1.1644 2.0172 0.0000| |Cr - 128| | ||
| 57 | */ | ||
| 58 | CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000), | ||
| 59 | CSC0_COEF1_A3(0x199) | CSC0_COEF1_B1(0x12a), | ||
| 60 | CSC0_COEF2_B2(0x79c) | CSC0_COEF2_B3(0x730), | ||
| 61 | CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x204), | ||
| 62 | CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0), | ||
| 63 | CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), | ||
| 64 | }, | ||
| 65 | [DRM_COLOR_YCBCR_FULL_RANGE] = { | ||
| 66 | /* | ||
| 67 | * BT.601 full range: | ||
| 68 | * | ||
| 69 | * |R| |1.0000 0.0000 1.4020| |Y - 0 | | ||
| 70 | * |G| = |1.0000 -0.3441 -0.7141| * |Cb - 128| | ||
| 71 | * |B| |1.0000 1.7720 0.0000| |Cr - 128| | ||
| 72 | */ | ||
| 73 | CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000), | ||
| 74 | CSC0_COEF1_A3(0x167) | CSC0_COEF1_B1(0x100), | ||
| 75 | CSC0_COEF2_B2(0x7a8) | CSC0_COEF2_B3(0x749), | ||
| 76 | CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1c6), | ||
| 77 | CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000), | ||
| 78 | CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), | ||
| 79 | }, | ||
| 80 | }, | ||
| 81 | [DRM_COLOR_YCBCR_BT709] = { | ||
| 82 | [DRM_COLOR_YCBCR_LIMITED_RANGE] = { | ||
| 83 | /* | ||
| 84 | * Rec.709 limited range: | ||
| 85 | * | ||
| 86 | * |R| |1.1644 0.0000 1.7927| |Y - 16 | | ||
| 87 | * |G| = |1.1644 -0.2132 -0.5329| * |Cb - 128| | ||
| 88 | * |B| |1.1644 2.1124 0.0000| |Cr - 128| | ||
| 89 | */ | ||
| 90 | CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000), | ||
| 91 | CSC0_COEF1_A3(0x1cb) | CSC0_COEF1_B1(0x12a), | ||
| 92 | CSC0_COEF2_B2(0x7c9) | CSC0_COEF2_B3(0x778), | ||
| 93 | CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x21d), | ||
| 94 | CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0), | ||
| 95 | CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), | ||
| 96 | }, | ||
| 97 | [DRM_COLOR_YCBCR_FULL_RANGE] = { | ||
| 98 | /* | ||
| 99 | * Rec.709 full range: | ||
| 100 | * | ||
| 101 | * |R| |1.0000 0.0000 1.5748| |Y - 0 | | ||
| 102 | * |G| = |1.0000 -0.1873 -0.4681| * |Cb - 128| | ||
| 103 | * |B| |1.0000 1.8556 0.0000| |Cr - 128| | ||
| 104 | */ | ||
| 105 | CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000), | ||
| 106 | CSC0_COEF1_A3(0x193) | CSC0_COEF1_B1(0x100), | ||
| 107 | CSC0_COEF2_B2(0x7d0) | CSC0_COEF2_B3(0x788), | ||
| 108 | CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1db), | ||
| 109 | CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000), | ||
| 110 | CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), | ||
| 111 | }, | ||
| 112 | }, | ||
| 113 | [DRM_COLOR_YCBCR_BT2020] = { | ||
| 114 | [DRM_COLOR_YCBCR_LIMITED_RANGE] = { | ||
| 115 | /* | ||
| 116 | * BT.2020 limited range: | ||
| 117 | * | ||
| 118 | * |R| |1.1644 0.0000 1.6787| |Y - 16 | | ||
| 119 | * |G| = |1.1644 -0.1874 -0.6505| * |Cb - 128| | ||
| 120 | * |B| |1.1644 2.1418 0.0000| |Cr - 128| | ||
| 121 | */ | ||
| 122 | CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000), | ||
| 123 | CSC0_COEF1_A3(0x1ae) | CSC0_COEF1_B1(0x12a), | ||
| 124 | CSC0_COEF2_B2(0x7d0) | CSC0_COEF2_B3(0x759), | ||
| 125 | CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x224), | ||
| 126 | CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0), | ||
| 127 | CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), | ||
| 128 | }, | ||
| 129 | [DRM_COLOR_YCBCR_FULL_RANGE] = { | ||
| 130 | /* | ||
| 131 | * BT.2020 full range: | ||
| 132 | * | ||
| 133 | * |R| |1.0000 0.0000 1.4746| |Y - 0 | | ||
| 134 | * |G| = |1.0000 -0.1646 -0.5714| * |Cb - 128| | ||
| 135 | * |B| |1.0000 1.8814 0.0000| |Cr - 128| | ||
| 136 | */ | ||
| 137 | CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000), | ||
| 138 | CSC0_COEF1_A3(0x179) | CSC0_COEF1_B1(0x100), | ||
| 139 | CSC0_COEF2_B2(0x7d6) | CSC0_COEF2_B3(0x76e), | ||
| 140 | CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1e2), | ||
| 141 | CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000), | ||
| 142 | CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), | ||
| 143 | }, | ||
| 144 | }, | ||
| 145 | }; | ||
| 146 | |||
| 34 | static void lcdif_set_formats(struct lcdif_drm_private *lcdif, | 147 | static void lcdif_set_formats(struct lcdif_drm_private *lcdif, |
| 148 | struct drm_plane_state *plane_state, | ||
| 35 | const u32 bus_format) | 149 | const u32 bus_format) |
| 36 | { | 150 | { |
| 37 | struct drm_device *drm = lcdif->drm; | 151 | struct drm_device *drm = lcdif->drm; |
| 38 | const u32 format = lcdif->crtc.primary->state->fb->format->format; | 152 | const u32 format = plane_state->fb->format->format; |
| 39 | 153 | bool in_yuv = false; | |
| 40 | writel(CSC0_CTRL_BYPASS, lcdif->base + LCDC_V8_CSC0_CTRL); | 154 | bool out_yuv = false; |
| 41 | 155 | ||
| 42 | switch (bus_format) { | 156 | switch (bus_format) { |
| 43 | case MEDIA_BUS_FMT_RGB565_1X16: | 157 | case MEDIA_BUS_FMT_RGB565_1X16: |
| @@ -51,24 +165,7 @@ static void lcdif_set_formats(struct lcdif_drm_private *lcdif, · 7 unmodified lines | |||
| 51 | case MEDIA_BUS_FMT_UYVY8_1X16: | 165 | case MEDIA_BUS_FMT_UYVY8_1X16: |
| 52 | writel(DISP_PARA_LINE_PATTERN_UYVY_H, | 166 | writel(DISP_PARA_LINE_PATTERN_UYVY_H, |
| 53 | lcdif->base + LCDC_V8_DISP_PARA); | 167 | lcdif->base + LCDC_V8_DISP_PARA); |
| 54 | 168 | out_yuv = true; | |
| 55 | /* CSC: BT.601 Full Range RGB to YCbCr coefficients. */ | ||
| 56 | writel(CSC0_COEF0_A2(0x096) | CSC0_COEF0_A1(0x04c), | ||
| 57 | lcdif->base + LCDC_V8_CSC0_COEF0); | ||
| 58 | writel(CSC0_COEF1_B1(0x7d5) | CSC0_COEF1_A3(0x01d), | ||
| 59 | lcdif->base + LCDC_V8_CSC0_COEF1); | ||
| 60 | writel(CSC0_COEF2_B3(0x080) | CSC0_COEF2_B2(0x7ac), | ||
| 61 | lcdif->base + LCDC_V8_CSC0_COEF2); | ||
| 62 | writel(CSC0_COEF3_C2(0x795) | CSC0_COEF3_C1(0x080), | ||
| 63 | lcdif->base + LCDC_V8_CSC0_COEF3); | ||
| 64 | writel(CSC0_COEF4_D1(0x000) | CSC0_COEF4_C3(0x7ec), | ||
| 65 | lcdif->base + LCDC_V8_CSC0_COEF4); | ||
| 66 | writel(CSC0_COEF5_D3(0x080) | CSC0_COEF5_D2(0x080), | ||
| 67 | lcdif->base + LCDC_V8_CSC0_COEF5); | ||
| 68 | |||
| 69 | writel(CSC0_CTRL_CSC_MODE_RGB2YCbCr, | ||
| 70 | lcdif->base + LCDC_V8_CSC0_CTRL); | ||
| 71 | |||
| 72 | break; | 169 | break; |
| 73 | default: | 170 | default: |
| 74 | dev_err(drm->dev, "Unknown media bus format 0x%x\n", bus_format); | 171 | dev_err(drm->dev, "Unknown media bus format 0x%x\n", bus_format); |
| @@ -76,6 +173,7 @@ static void lcdif_set_formats(struct lcdif_drm_private *lcdif, · 1 unmodified line | |||
| 76 | } | 173 | } |
| 77 | 174 | ||
| 78 | switch (format) { | 175 | switch (format) { |
| 176 | /* RGB Formats */ | ||
| 79 | case DRM_FORMAT_RGB565: | 177 | case DRM_FORMAT_RGB565: |
| 80 | writel(CTRLDESCL0_5_BPP_16_RGB565, | 178 | writel(CTRLDESCL0_5_BPP_16_RGB565, |
| 81 | lcdif->base + LCDC_V8_CTRLDESCL0_5); | 179 | lcdif->base + LCDC_V8_CTRLDESCL0_5); |
| @@ -100,10 +198,84 @@ static void lcdif_set_formats(struct lcdif_drm_private *lcdif, · 18 unmodified lines | |||
| 100 | writel(CTRLDESCL0_5_BPP_32_ARGB8888, | 198 | writel(CTRLDESCL0_5_BPP_32_ARGB8888, |
| 101 | lcdif->base + LCDC_V8_CTRLDESCL0_5); | 199 | lcdif->base + LCDC_V8_CTRLDESCL0_5); |
| 102 | break; | 200 | break; |
| 201 | |||
| 202 | /* YUV Formats */ | ||
| 203 | case DRM_FORMAT_YUYV: | ||
| 204 | writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_VY2UY1, | ||
| 205 | lcdif->base + LCDC_V8_CTRLDESCL0_5); | ||
| 206 | in_yuv = true; | ||
| 207 | break; | ||
| 208 | case DRM_FORMAT_YVYU: | ||
| 209 | writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_UY2VY1, | ||
| 210 | lcdif->base + LCDC_V8_CTRLDESCL0_5); | ||
| 211 | in_yuv = true; | ||
| 212 | break; | ||
| 213 | case DRM_FORMAT_UYVY: | ||
| 214 | writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_Y2VY1U, | ||
| 215 | lcdif->base + LCDC_V8_CTRLDESCL0_5); | ||
| 216 | in_yuv = true; | ||
| 217 | break; | ||
| 218 | case DRM_FORMAT_VYUY: | ||
| 219 | writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_Y2UY1V, | ||
| 220 | lcdif->base + LCDC_V8_CTRLDESCL0_5); | ||
| 221 | in_yuv = true; | ||
| 222 | break; | ||
| 223 | |||
| 103 | default: | 224 | default: |
| 104 | dev_err(drm->dev, "Unknown pixel format 0x%x\n", format); | 225 | dev_err(drm->dev, "Unknown pixel format 0x%x\n", format); |
| 105 | break; | 226 | break; |
| 106 | } | 227 | } |
| 228 | |||
| 229 | /* | ||
| 230 | * The CSC differentiates between "YCbCr" and "YUV", but the reference | ||
| 231 | * manual doesn't detail how they differ. Experiments showed that the | ||
| 232 | * luminance value is unaffected, only the calculations involving chroma | ||
| 233 | * values differ. The YCbCr mode behaves as expected, with chroma values | ||
| 234 | * being offset by 128. The YUV mode isn't fully understood. | ||
| 235 | */ | ||
| 236 | if (!in_yuv && out_yuv) { | ||
| 237 | /* RGB -> YCbCr */ | ||
| 238 | writel(CSC0_CTRL_CSC_MODE_RGB2YCbCr, | ||
| 239 | lcdif->base + LCDC_V8_CSC0_CTRL); | ||
| 240 | |||
| 241 | /* | ||
| 242 | * CSC: BT.601 Limited Range RGB to YCbCr coefficients. | ||
| 243 | * | ||
| 244 | * |Y | | 0.2568 0.5041 0.0979| |R| |16 | | ||
| 245 | * |Cb| = |-0.1482 -0.2910 0.4392| * |G| + |128| | ||
| 246 | * |Cr| | 0.4392 0.4392 -0.3678| |B| |128| | ||
| 247 | */ | ||
| 248 | writel(CSC0_COEF0_A2(0x081) | CSC0_COEF0_A1(0x041), | ||
| 249 | lcdif->base + LCDC_V8_CSC0_COEF0); | ||
| 250 | writel(CSC0_COEF1_B1(0x7db) | CSC0_COEF1_A3(0x019), | ||
| 251 | lcdif->base + LCDC_V8_CSC0_COEF1); | ||
| 252 | writel(CSC0_COEF2_B3(0x070) | CSC0_COEF2_B2(0x7b6), | ||
| 253 | lcdif->base + LCDC_V8_CSC0_COEF2); | ||
| 254 | writel(CSC0_COEF3_C2(0x7a2) | CSC0_COEF3_C1(0x070), | ||
| 255 | lcdif->base + LCDC_V8_CSC0_COEF3); | ||
| 256 | writel(CSC0_COEF4_D1(0x010) | CSC0_COEF4_C3(0x7ee), | ||
| 257 | lcdif->base + LCDC_V8_CSC0_COEF4); | ||
| 258 | writel(CSC0_COEF5_D3(0x080) | CSC0_COEF5_D2(0x080), | ||
| 259 | lcdif->base + LCDC_V8_CSC0_COEF5); | ||
| 260 | } else if (in_yuv && !out_yuv) { | ||
| 261 | /* YCbCr -> RGB */ | ||
| 262 | const u32 *coeffs = | ||
| 263 | lcdif_yuv2rgb_coeffs[plane_state->color_encoding] | ||
| 264 | [plane_state->color_range]; | ||
| 265 | |||
| 266 | writel(CSC0_CTRL_CSC_MODE_YCbCr2RGB, | ||
| 267 | lcdif->base + LCDC_V8_CSC0_CTRL); | ||
| 268 | |||
| 269 | writel(coeffs[0], lcdif->base + LCDC_V8_CSC0_COEF0); | ||
| 270 | writel(coeffs[1], lcdif->base + LCDC_V8_CSC0_COEF1); | ||
| 271 | writel(coeffs[2], lcdif->base + LCDC_V8_CSC0_COEF2); | ||
| 272 | writel(coeffs[3], lcdif->base + LCDC_V8_CSC0_COEF3); | ||
| 273 | writel(coeffs[4], lcdif->base + LCDC_V8_CSC0_COEF4); | ||
| 274 | writel(coeffs[5], lcdif->base + LCDC_V8_CSC0_COEF5); | ||
| 275 | } else { | ||
| 276 | /* RGB -> RGB, YCbCr -> YCbCr: bypass colorspace converter. */ | ||
| 277 | writel(CSC0_CTRL_BYPASS, lcdif->base + LCDC_V8_CSC0_CTRL); | ||
| 278 | } | ||
| 107 | } | 279 | } |
| 108 | 280 | ||
| 109 | static void lcdif_set_mode(struct lcdif_drm_private *lcdif, u32 bus_flags) | 281 | static void lcdif_set_mode(struct lcdif_drm_private *lcdif, u32 bus_flags) |
| @@ -188,6 +360,7 @@ static void lcdif_reset_block(struct lcdif_drm_private *lcdif) · 78 unmodified lines | |||
| 188 | } | 360 | } |
| 189 | 361 | ||
| 190 | static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif, | 362 | static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif, |
| 363 | struct drm_plane_state *plane_state, | ||
| 191 | struct drm_bridge_state *bridge_state, | 364 | struct drm_bridge_state *bridge_state, |
| 192 | const u32 bus_format) | 365 | const u32 bus_format) |
| 193 | { | 366 | { |
| @@ -210,7 +383,7 @@ static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif, · 16 unmodified lines | |||
| 210 | /* Mandatory eLCDIF reset as per the Reference Manual */ | 383 | /* Mandatory eLCDIF reset as per the Reference Manual */ |
| 211 | lcdif_reset_block(lcdif); | 384 | lcdif_reset_block(lcdif); |
| 212 | 385 | ||
| 213 | lcdif_set_formats(lcdif, bus_format); | 386 | lcdif_set_formats(lcdif, plane_state, bus_format); |
| 214 | 387 | ||
| 215 | lcdif_set_mode(lcdif, bus_flags); | 388 | lcdif_set_mode(lcdif, bus_flags); |
| 216 | } | 389 | } |
| @@ -293,7 +466,7 @@ static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc, · 76 unmodified lines | |||
| 293 | 466 | ||
| 294 | pm_runtime_get_sync(drm->dev); | 467 | pm_runtime_get_sync(drm->dev); |
| 295 | 468 | ||
| 296 | lcdif_crtc_mode_set_nofb(lcdif, bridge_state, bus_format); | 469 | lcdif_crtc_mode_set_nofb(lcdif, new_pstate, bridge_state, bus_format); |
| 297 | 470 | ||
| 298 | /* Write cur_buf as well to avoid an initial corrupt frame */ | 471 | /* Write cur_buf as well to avoid an initial corrupt frame */ |
| 299 | paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); | 472 | paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); |
| @@ -437,12 +610,19 @@ static const struct drm_plane_funcs lcdif_plane_funcs = { · 137 unmodified lines | |||
| 437 | }; | 610 | }; |
| 438 | 611 | ||
| 439 | static const u32 lcdif_primary_plane_formats[] = { | 612 | static const u32 lcdif_primary_plane_formats[] = { |
| 613 | /* RGB */ | ||
| 440 | DRM_FORMAT_RGB565, | 614 | DRM_FORMAT_RGB565, |
| 441 | DRM_FORMAT_RGB888, | 615 | DRM_FORMAT_RGB888, |
| 442 | DRM_FORMAT_XBGR8888, | 616 | DRM_FORMAT_XBGR8888, |
| 443 | DRM_FORMAT_XRGB1555, | 617 | DRM_FORMAT_XRGB1555, |
| 444 | DRM_FORMAT_XRGB4444, | 618 | DRM_FORMAT_XRGB4444, |
| 445 | DRM_FORMAT_XRGB8888, | 619 | DRM_FORMAT_XRGB8888, |
| 620 | |||
| 621 | /* Packed YCbCr */ | ||
| 622 | DRM_FORMAT_YUYV, | ||
| 623 | DRM_FORMAT_YVYU, | ||
| 624 | DRM_FORMAT_UYVY, | ||
| 625 | DRM_FORMAT_VYUY, | ||
| 446 | }; | 626 | }; |
| 447 | 627 | ||
| 448 | static const u64 lcdif_modifiers[] = { | 628 | static const u64 lcdif_modifiers[] = { |
| @@ -456,6 +636,11 @@ static const u64 lcdif_modifiers[] = { · 7 unmodified lines | |||
| 456 | 636 | ||
| 457 | int lcdif_kms_init(struct lcdif_drm_private *lcdif) | 637 | int lcdif_kms_init(struct lcdif_drm_private *lcdif) |
| 458 | { | 638 | { |
| 639 | const u32 supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) | | ||
| 640 | BIT(DRM_COLOR_YCBCR_BT709) | | ||
| 641 | BIT(DRM_COLOR_YCBCR_BT2020); | ||
| 642 | const u32 supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | | ||
| 643 | BIT(DRM_COLOR_YCBCR_FULL_RANGE); | ||
| 459 | struct drm_encoder *encoder = &lcdif->encoder; | 644 | struct drm_encoder *encoder = &lcdif->encoder; |
| 460 | struct drm_crtc *crtc = &lcdif->crtc; | 645 | struct drm_crtc *crtc = &lcdif->crtc; |
| 461 | int ret; | 646 | int ret; |
| @@ -471,6 +656,14 @@ int lcdif_kms_init(struct lcdif_drm_private *lcdif) · 9 unmodified lines | |||
| 471 | if (ret) | 656 | if (ret) |
| 472 | return ret; | 657 | return ret; |
| 473 | 658 | ||
| 659 | ret = drm_plane_create_color_properties(&lcdif->planes.primary, | ||
| 660 | supported_encodings, | ||
| 661 | supported_ranges, | ||
| 662 | DRM_COLOR_YCBCR_BT601, | ||
| 663 | DRM_COLOR_YCBCR_LIMITED_RANGE); | ||
| 664 | if (ret) | ||
| 665 | return ret; | ||
| 666 | |||
| 474 | drm_crtc_helper_add(crtc, &lcdif_crtc_helper_funcs); | 667 | drm_crtc_helper_add(crtc, &lcdif_crtc_helper_funcs); |
| 475 | ret = drm_crtc_init_with_planes(lcdif->drm, crtc, | 668 | ret = drm_crtc_init_with_planes(lcdif->drm, crtc, |
| 476 | &lcdif->planes.primary, NULL, | 669 | &lcdif->planes.primary, NULL, |
| @@ -130,7 +130,7 @@ · 129 unmodified lines | |||
| 130 | #define CTRL_FETCH_START_OPTION_BPV BIT(9) | 130 | #define CTRL_FETCH_START_OPTION_BPV BIT(9) |
| 131 | #define CTRL_FETCH_START_OPTION_RESV GENMASK(9, 8) | 131 | #define CTRL_FETCH_START_OPTION_RESV GENMASK(9, 8) |
| 132 | #define CTRL_FETCH_START_OPTION_MASK GENMASK(9, 8) | 132 | #define CTRL_FETCH_START_OPTION_MASK GENMASK(9, 8) |
| 133 | #define CTRL_NEG BIT(4) | 133 | #define CTRL_NEG BIT(4) |
| 134 | #define CTRL_INV_PXCK BIT(3) | 134 | #define CTRL_INV_PXCK BIT(3) |
| 135 | #define CTRL_INV_DE BIT(2) | 135 | #define CTRL_INV_DE BIT(2) |
| 136 | #define CTRL_INV_VS BIT(1) | 136 | #define CTRL_INV_VS BIT(1) |
| @@ -138,9 +138,9 @@ · 1 unmodified line | |||
| 138 | 138 | ||
| 139 | #define DISP_PARA_DISP_ON BIT(31) | 139 | #define DISP_PARA_DISP_ON BIT(31) |
| 140 | #define DISP_PARA_SWAP_EN BIT(30) | 140 | #define DISP_PARA_SWAP_EN BIT(30) |
| 141 | #define DISP_PARA_LINE_PATTERN_UYVY_H (GENMASK(29, 28) | BIT(26)) | 141 | #define DISP_PARA_LINE_PATTERN_UYVY_H (0xd << 26) |
| 142 | #define DISP_PARA_LINE_PATTERN_RGB565 GENMASK(28, 26) | 142 | #define DISP_PARA_LINE_PATTERN_RGB565 (0x7 << 26) |
| 143 | #define DISP_PARA_LINE_PATTERN_RGB888 0 | 143 | #define DISP_PARA_LINE_PATTERN_RGB888 (0x0 << 26) |
| 144 | #define DISP_PARA_LINE_PATTERN_MASK GENMASK(29, 26) | 144 | #define DISP_PARA_LINE_PATTERN_MASK GENMASK(29, 26) |
| 145 | #define DISP_PARA_DISP_MODE_MASK GENMASK(25, 24) | 145 | #define DISP_PARA_DISP_MODE_MASK GENMASK(25, 24) |
| 146 | #define DISP_PARA_BGND_R_MASK GENMASK(23, 16) | 146 | #define DISP_PARA_BGND_R_MASK GENMASK(23, 16) |
| @@ -186,7 +186,7 @@ · 39 unmodified lines | |||
| 186 | #define INT_ENABLE_D1_PLANE_PANIC_EN BIT(0) | 186 | #define INT_ENABLE_D1_PLANE_PANIC_EN BIT(0) |
| 187 | 187 | ||
| 188 | #define CTRLDESCL0_1_HEIGHT(n) (((n) & 0xffff) << 16) | 188 | #define CTRLDESCL0_1_HEIGHT(n) (((n) & 0xffff) << 16) |
| 189 | #define CTRLDESCL0_1_HEIGHT_MASK GENMASK(31, 16) | 189 | #define CTRLDESCL0_1_HEIGHT_MASK GENMASK(31, 16) |
| 190 | #define CTRLDESCL0_1_WIDTH(n) ((n) & 0xffff) | 190 | #define CTRLDESCL0_1_WIDTH(n) ((n) & 0xffff) |
| 191 | #define CTRLDESCL0_1_WIDTH_MASK GENMASK(15, 0) | 191 | #define CTRLDESCL0_1_WIDTH_MASK GENMASK(15, 0) |
| 192 | 192 | ||
| @@ -198,21 +198,24 @@ · 5 unmodified lines | |||
| 198 | 198 | ||
| 199 | #define CTRLDESCL0_5_EN BIT(31) | 199 | #define CTRLDESCL0_5_EN BIT(31) |
| 200 | #define CTRLDESCL0_5_SHADOW_LOAD_EN BIT(30) | 200 | #define CTRLDESCL0_5_SHADOW_LOAD_EN BIT(30) |
| 201 | #define CTRLDESCL0_5_BPP_16_RGB565 BIT(26) | 201 | #define CTRLDESCL0_5_BPP_16_RGB565 (0x4 << 24) |
| 202 | #define CTRLDESCL0_5_BPP_16_ARGB1555 (BIT(26) | BIT(24)) | 202 | #define CTRLDESCL0_5_BPP_16_ARGB1555 (0x5 << 24) |
| 203 | #define CTRLDESCL0_5_BPP_16_ARGB4444 (BIT(26) | BIT(25)) | 203 | #define CTRLDESCL0_5_BPP_16_ARGB4444 (0x6 << 24) |
| 204 | #define CTRLDESCL0_5_BPP_YCbCr422 (BIT(26) | BIT(25) | BIT(24)) | 204 | #define CTRLDESCL0_5_BPP_YCbCr422 (0x7 << 24) |
| 205 | #define CTRLDESCL0_5_BPP_24_RGB888 BIT(27) | 205 | #define CTRLDESCL0_5_BPP_24_RGB888 (0x8 << 24) |
| 206 | #define CTRLDESCL0_5_BPP_32_ARGB8888 (BIT(27) | BIT(24)) | 206 | #define CTRLDESCL0_5_BPP_32_ARGB8888 (0x9 << 24) |
| 207 | #define CTRLDESCL0_5_BPP_32_ABGR8888 (BIT(27) | BIT(25)) | 207 | #define CTRLDESCL0_5_BPP_32_ABGR8888 (0xa << 24) |
| 208 | #define CTRLDESCL0_5_BPP_MASK GENMASK(27, 24) | 208 | #define CTRLDESCL0_5_BPP_MASK GENMASK(27, 24) |
| 209 | #define CTRLDESCL0_5_YUV_FORMAT_Y2VY1U 0 | 209 | #define CTRLDESCL0_5_YUV_FORMAT_Y2VY1U (0x0 << 14) |
| 210 | #define CTRLDESCL0_5_YUV_FORMAT_Y2UY1V BIT(14) | 210 | #define CTRLDESCL0_5_YUV_FORMAT_Y2UY1V (0x1 << 14) |
| 211 | #define CTRLDESCL0_5_YUV_FORMAT_VY2UY1 BIT(15) | 211 | #define CTRLDESCL0_5_YUV_FORMAT_VY2UY1 (0x2 << 14) |
| 212 | #define CTRLDESCL0_5_YUV_FORMAT_UY2VY1 (BIT(15) | BIT(14)) | 212 | #define CTRLDESCL0_5_YUV_FORMAT_UY2VY1 (0x3 << 14) |
| 213 | #define CTRLDESCL0_5_YUV_FORMAT_MASK GENMASK(15, 14) | 213 | #define CTRLDESCL0_5_YUV_FORMAT_MASK GENMASK(15, 14) |
| 214 | 214 | ||
| 215 | #define CSC0_CTRL_CSC_MODE_RGB2YCbCr GENMASK(2, 1) | 215 | #define CSC0_CTRL_CSC_MODE_YUV2RGB (0x0 << 1) |
| 216 | #define CSC0_CTRL_CSC_MODE_YCbCr2RGB (0x1 << 1) | ||
| 217 | #define CSC0_CTRL_CSC_MODE_RGB2YUV (0x2 << 1) | ||
| 218 | #define CSC0_CTRL_CSC_MODE_RGB2YCbCr (0x3 << 1) | ||
| 216 | #define CSC0_CTRL_CSC_MODE_MASK GENMASK(2, 1) | 219 | #define CSC0_CTRL_CSC_MODE_MASK GENMASK(2, 1) |
| 217 | #define CSC0_CTRL_BYPASS BIT(0) | 220 | #define CSC0_CTRL_BYPASS BIT(0) |
| 218 | 221 | ||
| @@ -131,7 +131,7 @@ nv50_dmac_kick(struct nvif_push *push) · 130 unmodified lines | |||
| 131 | { | 131 | { |
| 132 | struct nv50_dmac *dmac = container_of(push, typeof(*dmac), _push); | 132 | struct nv50_dmac *dmac = container_of(push, typeof(*dmac), _push); |
| 133 | 133 | ||
| 134 | dmac->cur = push->cur - (u32 *)dmac->_push.mem.object.map.ptr; | 134 | dmac->cur = push->cur - (u32 __iomem *)dmac->_push.mem.object.map.ptr; |
| 135 | if (dmac->put != dmac->cur) { | 135 | if (dmac->put != dmac->cur) { |
| 136 | /* Push buffer fetches are not coherent with BAR1, we need to ensure | 136 | /* Push buffer fetches are not coherent with BAR1, we need to ensure |
| 137 | * writes have been flushed right through to VRAM before writing PUT. | 137 | * writes have been flushed right through to VRAM before writing PUT. |
| @@ -194,7 +194,7 @@ nv50_dmac_wait(struct nvif_push *push, u32 size) · 56 unmodified lines | |||
| 194 | if (WARN_ON(size > dmac->max)) | 194 | if (WARN_ON(size > dmac->max)) |
| 195 | return -EINVAL; | 195 | return -EINVAL; |
| 196 | 196 | ||
| 197 | dmac->cur = push->cur - (u32 *)dmac->_push.mem.object.map.ptr; | 197 | dmac->cur = push->cur - (u32 __iomem *)dmac->_push.mem.object.map.ptr; |
| 198 | if (dmac->cur + size >= dmac->max) { | 198 | if (dmac->cur + size >= dmac->max) { |
| 199 | int ret = nv50_dmac_wind(dmac); | 199 | int ret = nv50_dmac_wind(dmac); |
| 200 | if (ret) | 200 | if (ret) |
| @@ -672,7 +672,6 @@ nouveau_display_create(struct drm_device *dev) · 671 unmodified lines | |||
| 672 | drm_mode_create_dvi_i_properties(dev); | 672 | drm_mode_create_dvi_i_properties(dev); |
| 673 | 673 | ||
| 674 | dev->mode_config.funcs = &nouveau_mode_config_funcs; | 674 | dev->mode_config.funcs = &nouveau_mode_config_funcs; |
| 675 | dev->mode_config.fb_base = device->func->resource_addr(device, 1); | ||
| 676 | 675 | ||
| 677 | dev->mode_config.min_width = 0; | 676 | dev->mode_config.min_width = 0; |
| 678 | dev->mode_config.min_height = 0; | 677 | dev->mode_config.min_height = 0; |
| @@ -137,6 +137,8 @@ nv04_fbcon_accel_init(struct fb_info *info) · 136 unmodified lines | |||
| 137 | struct nouveau_channel *chan = drm->channel; | 137 | struct nouveau_channel *chan = drm->channel; |
| 138 | struct nvif_device *device = &drm->client.device; | 138 | struct nvif_device *device = &drm->client.device; |
| 139 | struct nvif_push *push = chan->chan.push; | 139 | struct nvif_push *push = chan->chan.push; |
| 140 | struct nvkm_device *nvkm_device = nvxx_device(&drm->client.device); | ||
| 141 | resource_size_t fb_base = nvkm_device->func->resource_addr(nvkm_device, 1); | ||
| 140 | int surface_fmt, pattern_fmt, rect_fmt; | 142 | int surface_fmt, pattern_fmt, rect_fmt; |
| 141 | int ret; | 143 | int ret; |
| 142 | 144 | ||
| @@ -210,8 +212,8 @@ nv04_fbcon_accel_init(struct fb_info *info) · 67 unmodified lines | |||
| 210 | 0x0188, chan->vram.handle); | 212 | 0x0188, chan->vram.handle); |
| 211 | PUSH_NVSQ(push, NV042, 0x0300, surface_fmt, | 213 | PUSH_NVSQ(push, NV042, 0x0300, surface_fmt, |
| 212 | 0x0304, info->fix.line_length | (info->fix.line_length << 16), | 214 | 0x0304, info->fix.line_length | (info->fix.line_length << 16), |
| 213 | 0x0308, info->fix.smem_start - dev->mode_config.fb_base, | 215 | 0x0308, info->fix.smem_start - fb_base, |
| 214 | 0x030c, info->fix.smem_start - dev->mode_config.fb_base); | 216 | 0x030c, info->fix.smem_start - fb_base); |
| 215 | 217 | ||
| 216 | PUSH_NVSQ(push, NV043, 0x0000, nfbdev->rop.handle); | 218 | PUSH_NVSQ(push, NV043, 0x0000, nfbdev->rop.handle); |
| 217 | PUSH_NVSQ(push, NV043, 0x0300, 0x55); | 219 | PUSH_NVSQ(push, NV043, 0x0300, 0x55); |
| @@ -177,8 +177,6 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, · 176 unmodified lines | |||
| 177 | 177 | ||
| 178 | drm_fb_helper_fill_info(fbi, helper, sizes); | 178 | drm_fb_helper_fill_info(fbi, helper, sizes); |
| 179 | 179 | ||
| 180 | dev->mode_config.fb_base = dma_addr; | ||
| 181 | |||
| 182 | fbi->screen_buffer = omap_gem_vaddr(fbdev->bo); | 180 | fbi->screen_buffer = omap_gem_vaddr(fbdev->bo); |
| 183 | fbi->screen_size = fbdev->bo->size; | 181 | fbi->screen_size = fbdev->bo->size; |
| 184 | fbi->fix.smem_start = dma_addr; | 182 | fbi->fix.smem_start = dma_addr; |
| @@ -125,7 +125,7 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, · 124 unmodified lines | |||
| 125 | 125 | ||
| 126 | get_dma_buf(dma_buf); | 126 | get_dma_buf(dma_buf); |
| 127 | 127 | ||
| 128 | sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE); | 128 | sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE); |
| 129 | if (IS_ERR(sgt)) { | 129 | if (IS_ERR(sgt)) { |
| 130 | ret = PTR_ERR(sgt); | 130 | ret = PTR_ERR(sgt); |
| 131 | goto fail_detach; | 131 | goto fail_detach; |
| @@ -142,7 +142,7 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, · 10 unmodified lines | |||
| 142 | return obj; | 142 | return obj; |
| 143 | 143 | ||
| 144 | fail_unmap: | 144 | fail_unmap: |
| 145 | dma_buf_unmap_attachment(attach, sgt, DMA_TO_DEVICE); | 145 | dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_TO_DEVICE); |
| 146 | fail_detach: | 146 | fail_detach: |
| 147 | dma_buf_detach(dma_buf, attach); | 147 | dma_buf_detach(dma_buf, attach); |
| 148 | dma_buf_put(dma_buf); | 148 | dma_buf_put(dma_buf); |
| @@ -331,9 +331,16 @@ static const struct of_device_id db7430_match[] = { · 330 unmodified lines | |||
| 331 | }; | 331 | }; |
| 332 | MODULE_DEVICE_TABLE(of, db7430_match); | 332 | MODULE_DEVICE_TABLE(of, db7430_match); |
| 333 | 333 | ||
| 334 | static const struct spi_device_id db7430_ids[] = { | ||
| 335 | { "lms397kf04" }, | ||
| 336 | { }, | ||
| 337 | }; | ||
| 338 | MODULE_DEVICE_TABLE(spi, db7430_ids); | ||
| 339 | |||
| 334 | static struct spi_driver db7430_driver = { | 340 | static struct spi_driver db7430_driver = { |
| 335 | .probe = db7430_probe, | 341 | .probe = db7430_probe, |
| 336 | .remove = db7430_remove, | 342 | .remove = db7430_remove, |
| 343 | .id_table = db7430_ids, | ||
| 337 | .driver = { | 344 | .driver = { |
| 338 | .name = "db7430-panel", | 345 | .name = "db7430-panel", |
| 339 | .of_match_table = db7430_match, | 346 | .of_match_table = db7430_match, |
| @@ -463,9 +463,16 @@ static const struct of_device_id tpg110_match[] = { · 462 unmodified lines | |||
| 463 | }; | 463 | }; |
| 464 | MODULE_DEVICE_TABLE(of, tpg110_match); | 464 | MODULE_DEVICE_TABLE(of, tpg110_match); |
| 465 | 465 | ||
| 466 | static const struct spi_device_id tpg110_ids[] = { | ||
| 467 | { "tpg110" }, | ||
| 468 | { }, | ||
| 469 | }; | ||
| 470 | MODULE_DEVICE_TABLE(spi, tpg110_ids); | ||
| 471 | |||
| 466 | static struct spi_driver tpg110_driver = { | 472 | static struct spi_driver tpg110_driver = { |
| 467 | .probe = tpg110_probe, | 473 | .probe = tpg110_probe, |
| 468 | .remove = tpg110_remove, | 474 | .remove = tpg110_remove, |
| 475 | .id_table = tpg110_ids, | ||
| 469 | .driver = { | 476 | .driver = { |
| 470 | .name = "tpo-tpg110-panel", | 477 | .name = "tpo-tpg110-panel", |
| 471 | .of_match_table = tpg110_match, | 478 | .of_match_table = tpg110_match, |
| @@ -425,9 +425,16 @@ static const struct of_device_id ws2401_match[] = { · 424 unmodified lines | |||
| 425 | }; | 425 | }; |
| 426 | MODULE_DEVICE_TABLE(of, ws2401_match); | 426 | MODULE_DEVICE_TABLE(of, ws2401_match); |
| 427 | 427 | ||
| 428 | static const struct spi_device_id ws2401_ids[] = { | ||
| 429 | { "lms380kf01" }, | ||
| 430 | { }, | ||
| 431 | }; | ||
| 432 | MODULE_DEVICE_TABLE(spi, ws2401_ids); | ||
| 433 | |||
| 428 | static struct spi_driver ws2401_driver = { | 434 | static struct spi_driver ws2401_driver = { |
| 429 | .probe = ws2401_probe, | 435 | .probe = ws2401_probe, |
| 430 | .remove = ws2401_remove, | 436 | .remove = ws2401_remove, |
| 437 | .id_table = ws2401_ids, | ||
| 431 | .driver = { | 438 | .driver = { |
| 432 | .name = "ws2401-panel", | 439 | .name = "ws2401-panel", |
| 433 | .of_match_table = ws2401_match, | 440 | .of_match_table = ws2401_match, |
| @@ -209,7 +209,7 @@ void panfrost_core_dump(struct panfrost_job *job) · 208 unmodified lines | |||
| 209 | goto dump_header; | 209 | goto dump_header; |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | ret = drm_gem_shmem_vmap(&bo->base, &map); | 212 | ret = drm_gem_vmap_unlocked(&bo->base.base, &map); |
| 213 | if (ret) { | 213 | if (ret) { |
| 214 | dev_err(pfdev->dev, "Panfrost Dump: couldn't map Buffer Object\n"); | 214 | dev_err(pfdev->dev, "Panfrost Dump: couldn't map Buffer Object\n"); |
| 215 | iter.hdr->bomap.valid = 0; | 215 | iter.hdr->bomap.valid = 0; |
| @@ -236,7 +236,7 @@ void panfrost_core_dump(struct panfrost_job *job) · 20 unmodified lines | |||
| 236 | vaddr = map.vaddr; | 236 | vaddr = map.vaddr; |
| 237 | memcpy(iter.data, vaddr, bo->base.base.size); | 237 | memcpy(iter.data, vaddr, bo->base.base.size); |
| 238 | 238 | ||
| 239 | drm_gem_shmem_vunmap(&bo->base, &map); | 239 | drm_gem_vunmap_unlocked(&bo->base.base, &map); |
| 240 | 240 | ||
| 241 | iter.hdr->bomap.valid = 1; | 241 | iter.hdr->bomap.valid = 1; |
| 242 | 242 | ||
| @@ -106,7 +106,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, · 105 unmodified lines | |||
| 106 | goto err_close_bo; | 106 | goto err_close_bo; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | ret = drm_gem_shmem_vmap(bo, &map); | 109 | ret = drm_gem_vmap_unlocked(&bo->base, &map); |
| 110 | if (ret) | 110 | if (ret) |
| 111 | goto err_put_mapping; | 111 | goto err_put_mapping; |
| 112 | perfcnt->buf = map.vaddr; | 112 | perfcnt->buf = map.vaddr; |
| @@ -165,7 +165,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, · 52 unmodified lines | |||
| 165 | return 0; | 165 | return 0; |
| 166 | 166 | ||
| 167 | err_vunmap: | 167 | err_vunmap: |
| 168 | drm_gem_shmem_vunmap(bo, &map); | 168 | drm_gem_vunmap_unlocked(&bo->base, &map); |
| 169 | err_put_mapping: | 169 | err_put_mapping: |
| 170 | panfrost_gem_mapping_put(perfcnt->mapping); | 170 | panfrost_gem_mapping_put(perfcnt->mapping); |
| 171 | err_close_bo: | 171 | err_close_bo: |
| @@ -195,7 +195,7 @@ static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev, · 23 unmodified lines | |||
| 195 | GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF)); | 195 | GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF)); |
| 196 | 196 | ||
| 197 | perfcnt->user = NULL; | 197 | perfcnt->user = NULL; |
| 198 | drm_gem_shmem_vunmap(&perfcnt->mapping->obj->base, &map); | 198 | drm_gem_vunmap_unlocked(&perfcnt->mapping->obj->base.base, &map); |
| 199 | perfcnt->buf = NULL; | 199 | perfcnt->buf = NULL; |
| 200 | panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv); | 200 | panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv); |
| 201 | panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu); | 201 | panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu); |
| @@ -1261,8 +1261,6 @@ int qxl_modeset_init(struct qxl_device *qdev) · 1260 unmodified lines | |||
| 1261 | qdev->ddev.mode_config.max_width = 8192; | 1261 | qdev->ddev.mode_config.max_width = 8192; |
| 1262 | qdev->ddev.mode_config.max_height = 8192; | 1262 | qdev->ddev.mode_config.max_height = 8192; |
| 1263 | 1263 | ||
| 1264 | qdev->ddev.mode_config.fb_base = qdev->vram_base; | ||
| 1265 | |||
| 1266 | drm_mode_create_suggested_offset_properties(&qdev->ddev); | 1264 | drm_mode_create_suggested_offset_properties(&qdev->ddev); |
| 1267 | qxl_mode_create_hotplug_mode_update_property(qdev); | 1265 | qxl_mode_create_hotplug_mode_update_property(qdev); |
| 1268 | 1266 | ||
| @@ -168,9 +168,16 @@ int qxl_bo_vmap_locked(struct qxl_bo *bo, struct iosys_map *map) · 167 unmodified lines | |||
| 168 | bo->map_count++; | 168 | bo->map_count++; |
| 169 | goto out; | 169 | goto out; |
| 170 | } | 170 | } |
| 171 | r = ttm_bo_vmap(&bo->tbo, &bo->map); | 171 | |
| 172 | r = __qxl_bo_pin(bo); | ||
| 172 | if (r) | 173 | if (r) |
| 173 | return r; | 174 | return r; |
| 175 | |||
| 176 | r = ttm_bo_vmap(&bo->tbo, &bo->map); | ||
| 177 | if (r) { | ||
| 178 | __qxl_bo_unpin(bo); | ||
| 179 | return r; | ||
| 180 | } | ||
| 174 | bo->map_count = 1; | 181 | bo->map_count = 1; |
| 175 | 182 | ||
| 176 | /* TODO: Remove kptr in favor of map everywhere. */ | 183 | /* TODO: Remove kptr in favor of map everywhere. */ |
| @@ -192,12 +199,6 @@ int qxl_bo_vmap(struct qxl_bo *bo, struct iosys_map *map) · 15 unmodified lines | |||
| 192 | if (r) | 199 | if (r) |
| 193 | return r; | 200 | return r; |
| 194 | 201 | ||
| 195 | r = __qxl_bo_pin(bo); | ||
| 196 | if (r) { | ||
| 197 | qxl_bo_unreserve(bo); | ||
| 198 | return r; | ||
| 199 | } | ||
| 200 | |||
| 201 | r = qxl_bo_vmap_locked(bo, map); | 202 | r = qxl_bo_vmap_locked(bo, map); |
| 202 | qxl_bo_unreserve(bo); | 203 | qxl_bo_unreserve(bo); |
| 203 | return r; | 204 | return r; |
| @@ -247,6 +248,7 @@ void qxl_bo_vunmap_locked(struct qxl_bo *bo) · 43 unmodified lines | |||
| 247 | return; | 248 | return; |
| 248 | bo->kptr = NULL; | 249 | bo->kptr = NULL; |
| 249 | ttm_bo_vunmap(&bo->tbo, &bo->map); | 250 | ttm_bo_vunmap(&bo->tbo, &bo->map); |
| 251 | __qxl_bo_unpin(bo); | ||
| 250 | } | 252 | } |
| 251 | 253 | ||
| 252 | int qxl_bo_vunmap(struct qxl_bo *bo) | 254 | int qxl_bo_vunmap(struct qxl_bo *bo) |
| @@ -258,7 +260,6 @@ int qxl_bo_vunmap(struct qxl_bo *bo) · 5 unmodified lines | |||
| 258 | return r; | 260 | return r; |
| 259 | 261 | ||
| 260 | qxl_bo_vunmap_locked(bo); | 262 | qxl_bo_vunmap_locked(bo); |
| 261 | __qxl_bo_unpin(bo); | ||
| 262 | qxl_bo_unreserve(bo); | 263 | qxl_bo_unreserve(bo); |
| 263 | return 0; | 264 | return 0; |
| 264 | } | 265 | } |
| @@ -59,7 +59,7 @@ int qxl_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) · 58 unmodified lines | |||
| 59 | struct qxl_bo *bo = gem_to_qxl_bo(obj); | 59 | struct qxl_bo *bo = gem_to_qxl_bo(obj); |
| 60 | int ret; | 60 | int ret; |
| 61 | 61 | ||
| 62 | ret = qxl_bo_vmap(bo, map); | 62 | ret = qxl_bo_vmap_locked(bo, map); |
| 63 | if (ret < 0) | 63 | if (ret < 0) |
| 64 | return ret; | 64 | return ret; |
| 65 | 65 | ||
| @@ -71,5 +71,5 @@ void qxl_gem_prime_vunmap(struct drm_gem_object *obj, · 5 unmodified lines | |||
| 71 | { | 71 | { |
| 72 | struct qxl_bo *bo = gem_to_qxl_bo(obj); | 72 | struct qxl_bo *bo = gem_to_qxl_bo(obj); |
| 73 | 73 | ||
| 74 | qxl_bo_vunmap(bo); | 74 | qxl_bo_vunmap_locked(bo); |
| 75 | } | 75 | } |
| @@ -1604,8 +1604,6 @@ int radeon_modeset_init(struct radeon_device *rdev) · 1603 unmodified lines | |||
| 1604 | 1604 | ||
| 1605 | rdev->ddev->mode_config.fb_modifiers_not_supported = true; | 1605 | rdev->ddev->mode_config.fb_modifiers_not_supported = true; |
| 1606 | 1606 | ||
| 1607 | rdev->ddev->mode_config.fb_base = rdev->mc.aper_base; | ||
| 1608 | |||
| 1609 | ret = radeon_modeset_create_props(rdev); | 1607 | ret = radeon_modeset_create_props(rdev); |
| 1610 | if (ret) { | 1608 | if (ret) { |
| 1611 | return ret; | 1609 | return ret; |
| @@ -276,7 +276,7 @@ static int radeonfb_create(struct drm_fb_helper *helper, · 275 unmodified lines | |||
| 276 | drm_fb_helper_fill_info(info, &rfbdev->helper, sizes); | 276 | drm_fb_helper_fill_info(info, &rfbdev->helper, sizes); |
| 277 | 277 | ||
| 278 | /* setup aperture base/size for vesafb takeover */ | 278 | /* setup aperture base/size for vesafb takeover */ |
| 279 | info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base; | 279 | info->apertures->ranges[0].base = rdev->mc.aper_base; |
| 280 | info->apertures->ranges[0].size = rdev->mc.aper_size; | 280 | info->apertures->ranges[0].size = rdev->mc.aper_size; |
| 281 | 281 | ||
| 282 | /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ | 282 | /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ |
| @@ -73,6 +73,7 @@ int drm_sched_entity_init(struct drm_sched_entity *entity, · 72 unmodified lines | |||
| 73 | entity->priority = priority; | 73 | entity->priority = priority; |
| 74 | entity->sched_list = num_sched_list > 1 ? sched_list : NULL; | 74 | entity->sched_list = num_sched_list > 1 ? sched_list : NULL; |
| 75 | entity->last_scheduled = NULL; | 75 | entity->last_scheduled = NULL; |
| 76 | RB_CLEAR_NODE(&entity->rb_tree_node); | ||
| 76 | 77 | ||
| 77 | if(num_sched_list) | 78 | if(num_sched_list) |
| 78 | entity->rq = &sched_list[0]->sched_rq[entity->priority]; | 79 | entity->rq = &sched_list[0]->sched_rq[entity->priority]; |
| @@ -207,6 +208,7 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, · 128 unmodified lines | |||
| 207 | struct drm_sched_job *job = container_of(cb, struct drm_sched_job, | 208 | struct drm_sched_job *job = container_of(cb, struct drm_sched_job, |
| 208 | finish_cb); | 209 | finish_cb); |
| 209 | 210 | ||
| 211 | dma_fence_put(f); | ||
| 210 | INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work); | 212 | INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work); |
| 211 | schedule_work(&job->work); | 213 | schedule_work(&job->work); |
| 212 | } | 214 | } |
| @@ -234,8 +236,10 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) · 21 unmodified lines | |||
| 234 | struct drm_sched_fence *s_fence = job->s_fence; | 236 | struct drm_sched_fence *s_fence = job->s_fence; |
| 235 | 237 | ||
| 236 | /* Wait for all dependencies to avoid data corruptions */ | 238 | /* Wait for all dependencies to avoid data corruptions */ |
| 237 | while ((f = drm_sched_job_dependency(job, entity))) | 239 | while ((f = drm_sched_job_dependency(job, entity))) { |
| 238 | dma_fence_wait(f, false); | 240 | dma_fence_wait(f, false); |
| 241 | dma_fence_put(f); | ||
| 242 | } | ||
| 239 | 243 | ||
| 240 | drm_sched_fence_scheduled(s_fence); | 244 | drm_sched_fence_scheduled(s_fence); |
| 241 | dma_fence_set_error(&s_fence->finished, -ESRCH); | 245 | dma_fence_set_error(&s_fence->finished, -ESRCH); |
| @@ -250,6 +254,7 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) · 8 unmodified lines | |||
| 250 | continue; | 254 | continue; |
| 251 | } | 255 | } |
| 252 | 256 | ||
| 257 | dma_fence_get(entity->last_scheduled); | ||
| 253 | r = dma_fence_add_callback(entity->last_scheduled, | 258 | r = dma_fence_add_callback(entity->last_scheduled, |
| 254 | &job->finish_cb, | 259 | &job->finish_cb, |
| 255 | drm_sched_entity_kill_jobs_cb); | 260 | drm_sched_entity_kill_jobs_cb); |
| @@ -444,6 +449,19 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity) · 188 unmodified lines | |||
| 444 | smp_wmb(); | 449 | smp_wmb(); |
| 445 | 450 | ||
| 446 | spsc_queue_pop(&entity->job_queue); | 451 | spsc_queue_pop(&entity->job_queue); |
| 452 | |||
| 453 | /* | ||
| 454 | * Update the entity's location in the min heap according to | ||
| 455 | * the timestamp of the next job, if any. | ||
| 456 | */ | ||
| 457 | if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) { | ||
| 458 | struct drm_sched_job *next; | ||
| 459 | |||
| 460 | next = to_drm_sched_job(spsc_queue_peek(&entity->job_queue)); | ||
| 461 | if (next) | ||
| 462 | drm_sched_rq_update_fifo(entity, next->submit_ts); | ||
| 463 | } | ||
| 464 | |||
| 447 | return sched_job; | 465 | return sched_job; |
| 448 | } | 466 | } |
| 449 | 467 | ||
| @@ -508,6 +526,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job) · 58 unmodified lines | |||
| 508 | atomic_inc(entity->rq->sched->score); | 526 | atomic_inc(entity->rq->sched->score); |
| 509 | WRITE_ONCE(entity->last_user, current->group_leader); | 527 | WRITE_ONCE(entity->last_user, current->group_leader); |
| 510 | first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node); | 528 | first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node); |
| 529 | sched_job->submit_ts = ktime_get(); | ||
| 511 | 530 | ||
| 512 | /* first job wakes up scheduler */ | 531 | /* first job wakes up scheduler */ |
| 513 | if (first) { | 532 | if (first) { |
| @@ -519,8 +538,13 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job) · 5 unmodified lines | |||
| 519 | DRM_ERROR("Trying to push to a killed entity\n"); | 538 | DRM_ERROR("Trying to push to a killed entity\n"); |
| 520 | return; | 539 | return; |
| 521 | } | 540 | } |
| 541 | |||
| 522 | drm_sched_rq_add_entity(entity->rq, entity); | 542 | drm_sched_rq_add_entity(entity->rq, entity); |
| 523 | spin_unlock(&entity->rq_lock); | 543 | spin_unlock(&entity->rq_lock); |
| 544 | |||
| 545 | if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) | ||
| 546 | drm_sched_rq_update_fifo(entity, sched_job->submit_ts); | ||
| 547 | |||
| 524 | drm_sched_wakeup(entity->rq->sched); | 548 | drm_sched_wakeup(entity->rq->sched); |
| 525 | } | 549 | } |
| 526 | } | 550 | } |
| @@ -62,6 +62,55 @@ · 61 unmodified lines | |||
| 62 | #define to_drm_sched_job(sched_job) \ | 62 | #define to_drm_sched_job(sched_job) \ |
| 63 | container_of((sched_job), struct drm_sched_job, queue_node) | 63 | container_of((sched_job), struct drm_sched_job, queue_node) |
| 64 | 64 | ||
| 65 | int drm_sched_policy = DRM_SCHED_POLICY_RR; | ||
| 66 | |||
| 67 | /** | ||
| 68 | * DOC: sched_policy (int) | ||
| 69 | * Used to override default entities scheduling policy in a run queue. | ||
| 70 | */ | ||
| 71 | MODULE_PARM_DESC(sched_policy, "Specify schedule policy for entities on a runqueue, " __stringify(DRM_SCHED_POLICY_RR) " = Round Robin (default), " __stringify(DRM_SCHED_POLICY_FIFO) " = use FIFO."); | ||
| 72 | module_param_named(sched_policy, drm_sched_policy, int, 0444); | ||
| 73 | |||
| 74 | static __always_inline bool drm_sched_entity_compare_before(struct rb_node *a, | ||
| 75 | const struct rb_node *b) | ||
| 76 | { | ||
| 77 | struct drm_sched_entity *ent_a = rb_entry((a), struct drm_sched_entity, rb_tree_node); | ||
| 78 | struct drm_sched_entity *ent_b = rb_entry((b), struct drm_sched_entity, rb_tree_node); | ||
| 79 | |||
| 80 | return ktime_before(ent_a->oldest_job_waiting, ent_b->oldest_job_waiting); | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline void drm_sched_rq_remove_fifo_locked(struct drm_sched_entity *entity) | ||
| 84 | { | ||
| 85 | struct drm_sched_rq *rq = entity->rq; | ||
| 86 | |||
| 87 | if (!RB_EMPTY_NODE(&entity->rb_tree_node)) { | ||
| 88 | rb_erase_cached(&entity->rb_tree_node, &rq->rb_tree_root); | ||
| 89 | RB_CLEAR_NODE(&entity->rb_tree_node); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | void drm_sched_rq_update_fifo(struct drm_sched_entity *entity, ktime_t ts) | ||
| 94 | { | ||
| 95 | /* | ||
| 96 | * Both locks need to be grabbed, one to protect from entity->rq change | ||
| 97 | * for entity from within concurrent drm_sched_entity_select_rq and the | ||
| 98 | * other to update the rb tree structure. | ||
| 99 | */ | ||
| 100 | spin_lock(&entity->rq_lock); | ||
| 101 | spin_lock(&entity->rq->lock); | ||
| 102 | |||
| 103 | drm_sched_rq_remove_fifo_locked(entity); | ||
| 104 | |||
| 105 | entity->oldest_job_waiting = ts; | ||
| 106 | |||
| 107 | rb_add_cached(&entity->rb_tree_node, &entity->rq->rb_tree_root, | ||
| 108 | drm_sched_entity_compare_before); | ||
| 109 | |||
| 110 | spin_unlock(&entity->rq->lock); | ||
| 111 | spin_unlock(&entity->rq_lock); | ||
| 112 | } | ||
| 113 | |||
| 65 | /** | 114 | /** |
| 66 | * drm_sched_rq_init - initialize a given run queue struct | 115 | * drm_sched_rq_init - initialize a given run queue struct |
| 67 | * | 116 | * |
| @@ -75,6 +124,7 @@ static void drm_sched_rq_init(struct drm_gpu_scheduler *sched, · 7 unmodified lines | |||
| 75 | { | 124 | { |
| 76 | spin_lock_init(&rq->lock); | 125 | spin_lock_init(&rq->lock); |
| 77 | INIT_LIST_HEAD(&rq->entities); | 126 | INIT_LIST_HEAD(&rq->entities); |
| 127 | rq->rb_tree_root = RB_ROOT_CACHED; | ||
| 78 | rq->current_entity = NULL; | 128 | rq->current_entity = NULL; |
| 79 | rq->sched = sched; | 129 | rq->sched = sched; |
| 80 | } | 130 | } |
| @@ -92,9 +142,12 @@ void drm_sched_rq_add_entity(struct drm_sched_rq *rq, · 11 unmodified lines | |||
| 92 | { | 142 | { |
| 93 | if (!list_empty(&entity->list)) | 143 | if (!list_empty(&entity->list)) |
| 94 | return; | 144 | return; |
| 145 | |||
| 95 | spin_lock(&rq->lock); | 146 | spin_lock(&rq->lock); |
| 147 | |||
| 96 | atomic_inc(rq->sched->score); | 148 | atomic_inc(rq->sched->score); |
| 97 | list_add_tail(&entity->list, &rq->entities); | 149 | list_add_tail(&entity->list, &rq->entities); |
| 150 | |||
| 98 | spin_unlock(&rq->lock); | 151 | spin_unlock(&rq->lock); |
| 99 | } | 152 | } |
| 100 | 153 | ||
| @@ -111,23 +164,30 @@ void drm_sched_rq_remove_entity(struct drm_sched_rq *rq, · 10 unmodified lines | |||
| 111 | { | 164 | { |
| 112 | if (list_empty(&entity->list)) | 165 | if (list_empty(&entity->list)) |
| 113 | return; | 166 | return; |
| 167 | |||
| 114 | spin_lock(&rq->lock); | 168 | spin_lock(&rq->lock); |
| 169 | |||
| 115 | atomic_dec(rq->sched->score); | 170 | atomic_dec(rq->sched->score); |
| 116 | list_del_init(&entity->list); | 171 | list_del_init(&entity->list); |
| 172 | |||
| 117 | if (rq->current_entity == entity) | 173 | if (rq->current_entity == entity) |
| 118 | rq->current_entity = NULL; | 174 | rq->current_entity = NULL; |
| 175 | |||
| 176 | if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) | ||
| 177 | drm_sched_rq_remove_fifo_locked(entity); | ||
| 178 | |||
| 119 | spin_unlock(&rq->lock); | 179 | spin_unlock(&rq->lock); |
| 120 | } | 180 | } |
| 121 | 181 | ||
| 122 | /** | 182 | /** |
| 123 | * drm_sched_rq_select_entity - Select an entity which could provide a job to run | 183 | * drm_sched_rq_select_entity_rr - Select an entity which could provide a job to run |
| 124 | * | 184 | * |
| 125 | * @rq: scheduler run queue to check. | 185 | * @rq: scheduler run queue to check. |
| 126 | * | 186 | * |
| 127 | * Try to find a ready entity, returns NULL if none found. | 187 | * Try to find a ready entity, returns NULL if none found. |
| 128 | */ | 188 | */ |
| 129 | static struct drm_sched_entity * | 189 | static struct drm_sched_entity * |
| 130 | drm_sched_rq_select_entity(struct drm_sched_rq *rq) | 190 | drm_sched_rq_select_entity_rr(struct drm_sched_rq *rq) |
| 131 | { | 191 | { |
| 132 | struct drm_sched_entity *entity; | 192 | struct drm_sched_entity *entity; |
| 133 | 193 | ||
| @@ -163,6 +223,34 @@ drm_sched_rq_select_entity(struct drm_sched_rq *rq) · 29 unmodified lines | |||
| 163 | return NULL; | 223 | return NULL; |
| 164 | } | 224 | } |
| 165 | 225 | ||
| 226 | /** | ||
| 227 | * drm_sched_rq_select_entity_fifo - Select an entity which provides a job to run | ||
| 228 | * | ||
| 229 | * @rq: scheduler run queue to check. | ||
| 230 | * | ||
| 231 | * Find oldest waiting ready entity, returns NULL if none found. | ||
| 232 | */ | ||
| 233 | static struct drm_sched_entity * | ||
| 234 | drm_sched_rq_select_entity_fifo(struct drm_sched_rq *rq) | ||
| 235 | { | ||
| 236 | struct rb_node *rb; | ||
| 237 | |||
| 238 | spin_lock(&rq->lock); | ||
| 239 | for (rb = rb_first_cached(&rq->rb_tree_root); rb; rb = rb_next(rb)) { | ||
| 240 | struct drm_sched_entity *entity; | ||
| 241 | |||
| 242 | entity = rb_entry(rb, struct drm_sched_entity, rb_tree_node); | ||
| 243 | if (drm_sched_entity_is_ready(entity)) { | ||
| 244 | rq->current_entity = entity; | ||
| 245 | reinit_completion(&entity->entity_idle); | ||
| 246 | break; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | spin_unlock(&rq->lock); | ||
| 250 | |||
| 251 | return rb ? rb_entry(rb, struct drm_sched_entity, rb_tree_node) : NULL; | ||
| 252 | } | ||
| 253 | |||
| 166 | /** | 254 | /** |
| 167 | * drm_sched_job_done - complete a job | 255 | * drm_sched_job_done - complete a job |
| 168 | * @s_job: pointer to the job which is done | 256 | * @s_job: pointer to the job which is done |
| @@ -803,7 +891,9 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) · 634 unmodified lines | |||
| 803 | 891 | ||
| 804 | /* Kernel run queue has higher priority than normal run queue*/ | 892 | /* Kernel run queue has higher priority than normal run queue*/ |
| 805 | for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { | 893 | for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { |
| 806 | entity = drm_sched_rq_select_entity(&sched->sched_rq[i]); | 894 | entity = drm_sched_policy == DRM_SCHED_POLICY_FIFO ? |
| 895 | drm_sched_rq_select_entity_fifo(&sched->sched_rq[i]) : | ||
| 896 | drm_sched_rq_select_entity_rr(&sched->sched_rq[i]); | ||
| 807 | if (entity) | 897 | if (entity) |
| 808 | break; | 898 | break; |
| 809 | } | 899 | } |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | #include <drm/drm_atomic.h> | 21 | #include <drm/drm_atomic.h> |
| 22 | #include <drm/drm_atomic_helper.h> | 22 | #include <drm/drm_atomic_helper.h> |
| 23 | #include <drm/drm_crtc_helper.h> | ||
| 23 | #include <drm/drm_damage_helper.h> | 24 | #include <drm/drm_damage_helper.h> |
| 24 | #include <drm/drm_edid.h> | 25 | #include <drm/drm_edid.h> |
| 25 | #include <drm/drm_fb_helper.h> | 26 | #include <drm/drm_fb_helper.h> |
| @@ -578,21 +579,24 @@ static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane, · 552 unmodified lines | |||
| 578 | struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); | 579 | struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); |
| 579 | struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); | 580 | struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); |
| 580 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); | 581 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); |
| 582 | struct drm_atomic_helper_damage_iter iter; | ||
| 581 | struct drm_device *drm = plane->dev; | 583 | struct drm_device *drm = plane->dev; |
| 582 | struct drm_rect src_clip, dst_clip; | 584 | struct drm_rect dst_clip; |
| 585 | struct drm_rect damage; | ||
| 583 | int idx; | 586 | int idx; |
| 584 | 587 | ||
| 585 | if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip)) | 588 | if (!drm_dev_enter(drm, &idx)) |
| 586 | return; | 589 | return; |
| 587 | 590 | ||
| 588 | dst_clip = plane_state->dst; | 591 | drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); |
| 589 | if (!drm_rect_intersect(&dst_clip, &src_clip)) | 592 | drm_atomic_for_each_plane_damage(&iter, &damage) { |
| 590 | return; | 593 | dst_clip = plane_state->dst; |
| 591 | 594 | ||
| 592 | if (!drm_dev_enter(drm, &idx)) | 595 | if (!drm_rect_intersect(&dst_clip, &damage)) |
| 593 | return; | 596 | continue; |
| 594 | 597 | ||
| 595 | ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip); | 598 | ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip); |
| 599 | } | ||
| 596 | 600 | ||
| 597 | drm_dev_exit(idx); | 601 | drm_dev_exit(idx); |
| 598 | } | 602 | } |
| @@ -642,19 +646,6 @@ static enum drm_mode_status ssd130x_crtc_helper_mode_valid(struct drm_crtc *crtc · 43 unmodified lines | |||
| 642 | return MODE_OK; | 646 | return MODE_OK; |
| 643 | } | 647 | } |
| 644 | 648 | ||
| 645 | static int ssd130x_crtc_helper_atomic_check(struct drm_crtc *crtc, | ||
| 646 | struct drm_atomic_state *new_state) | ||
| 647 | { | ||
| 648 | struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); | ||
| 649 | int ret; | ||
| 650 | |||
| 651 | ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); | ||
| 652 | if (ret) | ||
| 653 | return ret; | ||
| 654 | |||
| 655 | return drm_atomic_add_affected_planes(new_state, crtc); | ||
| 656 | } | ||
| 657 | |||
| 658 | /* | 649 | /* |
| 659 | * The CRTC is always enabled. Screen updates are performed by | 650 | * The CRTC is always enabled. Screen updates are performed by |
| 660 | * the primary plane's atomic_update function. Disabling clears | 651 | * the primary plane's atomic_update function. Disabling clears |
| @@ -662,7 +653,7 @@ static int ssd130x_crtc_helper_atomic_check(struct drm_crtc *crtc, · 1 unmodified line | |||
| 662 | */ | 653 | */ |
| 663 | static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs = { | 654 | static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs = { |
| 664 | .mode_valid = ssd130x_crtc_helper_mode_valid, | 655 | .mode_valid = ssd130x_crtc_helper_mode_valid, |
| 665 | .atomic_check = ssd130x_crtc_helper_atomic_check, | 656 | .atomic_check = drm_crtc_helper_atomic_check, |
| 666 | }; | 657 | }; |
| 667 | 658 | ||
| 668 | static void ssd130x_crtc_reset(struct drm_crtc *crtc) | 659 | static void ssd130x_crtc_reset(struct drm_crtc *crtc) |
| @@ -280,7 +280,6 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, · 279 unmodified lines | |||
| 280 | } | 280 | } |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | drm->mode_config.fb_base = (resource_size_t)bo->iova; | ||
| 284 | info->screen_base = (void __iomem *)bo->vaddr + offset; | 283 | info->screen_base = (void __iomem *)bo->vaddr + offset; |
| 285 | info->screen_size = size; | 284 | info->screen_size = size; |
| 286 | info->fix.smem_start = (unsigned long)(bo->iova + offset); | 285 | info->fix.smem_start = (unsigned long)(bo->iova + offset); |
| @@ -84,7 +84,7 @@ static struct host1x_bo_mapping *tegra_bo_pin(struct device *dev, struct host1x_ · 83 unmodified lines | |||
| 84 | goto free; | 84 | goto free; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | map->sgt = dma_buf_map_attachment(map->attach, direction); | 87 | map->sgt = dma_buf_map_attachment_unlocked(map->attach, direction); |
| 88 | if (IS_ERR(map->sgt)) { | 88 | if (IS_ERR(map->sgt)) { |
| 89 | dma_buf_detach(buf, map->attach); | 89 | dma_buf_detach(buf, map->attach); |
| 90 | err = PTR_ERR(map->sgt); | 90 | err = PTR_ERR(map->sgt); |
| @@ -160,7 +160,8 @@ free: · 69 unmodified lines | |||
| 160 | static void tegra_bo_unpin(struct host1x_bo_mapping *map) | 160 | static void tegra_bo_unpin(struct host1x_bo_mapping *map) |
| 161 | { | 161 | { |
| 162 | if (map->attach) { | 162 | if (map->attach) { |
| 163 | dma_buf_unmap_attachment(map->attach, map->sgt, map->direction); | 163 | dma_buf_unmap_attachment_unlocked(map->attach, map->sgt, |
| 164 | map->direction); | ||
| 164 | dma_buf_detach(map->attach->dmabuf, map->attach); | 165 | dma_buf_detach(map->attach->dmabuf, map->attach); |
| 165 | } else { | 166 | } else { |
| 166 | dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0); | 167 | dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0); |
| @@ -181,7 +182,7 @@ static void *tegra_bo_mmap(struct host1x_bo *bo) · 14 unmodified lines | |||
| 181 | if (obj->vaddr) { | 182 | if (obj->vaddr) { |
| 182 | return obj->vaddr; | 183 | return obj->vaddr; |
| 183 | } else if (obj->gem.import_attach) { | 184 | } else if (obj->gem.import_attach) { |
| 184 | ret = dma_buf_vmap(obj->gem.import_attach->dmabuf, &map); | 185 | ret = dma_buf_vmap_unlocked(obj->gem.import_attach->dmabuf, &map); |
| 185 | return ret ? NULL : map.vaddr; | 186 | return ret ? NULL : map.vaddr; |
| 186 | } else { | 187 | } else { |
| 187 | return vmap(obj->pages, obj->num_pages, VM_MAP, | 188 | return vmap(obj->pages, obj->num_pages, VM_MAP, |
| @@ -197,7 +198,7 @@ static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) · 9 unmodified lines | |||
| 197 | if (obj->vaddr) | 198 | if (obj->vaddr) |
| 198 | return; | 199 | return; |
| 199 | else if (obj->gem.import_attach) | 200 | else if (obj->gem.import_attach) |
| 200 | dma_buf_vunmap(obj->gem.import_attach->dmabuf, &map); | 201 | dma_buf_vunmap_unlocked(obj->gem.import_attach->dmabuf, &map); |
| 201 | else | 202 | else |
| 202 | vunmap(addr); | 203 | vunmap(addr); |
| 203 | } | 204 | } |
| @@ -461,7 +462,7 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm, · 257 unmodified lines | |||
| 461 | 462 | ||
| 462 | get_dma_buf(buf); | 463 | get_dma_buf(buf); |
| 463 | 464 | ||
| 464 | bo->sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE); | 465 | bo->sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE); |
| 465 | if (IS_ERR(bo->sgt)) { | 466 | if (IS_ERR(bo->sgt)) { |
| 466 | err = PTR_ERR(bo->sgt); | 467 | err = PTR_ERR(bo->sgt); |
| 467 | goto detach; | 468 | goto detach; |
| @@ -479,7 +480,7 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm, · 11 unmodified lines | |||
| 479 | 480 | ||
| 480 | detach: | 481 | detach: |
| 481 | if (!IS_ERR_OR_NULL(bo->sgt)) | 482 | if (!IS_ERR_OR_NULL(bo->sgt)) |
| 482 | dma_buf_unmap_attachment(attach, bo->sgt, DMA_TO_DEVICE); | 483 | dma_buf_unmap_attachment_unlocked(attach, bo->sgt, DMA_TO_DEVICE); |
| 483 | 484 | ||
| 484 | dma_buf_detach(buf, attach); | 485 | dma_buf_detach(buf, attach); |
| 485 | dma_buf_put(buf); | 486 | dma_buf_put(buf); |
| @@ -508,8 +509,8 @@ void tegra_bo_free_object(struct drm_gem_object *gem) · 22 unmodified lines | |||
| 508 | tegra_bo_iommu_unmap(tegra, bo); | 509 | tegra_bo_iommu_unmap(tegra, bo); |
| 509 | 510 | ||
| 510 | if (gem->import_attach) { | 511 | if (gem->import_attach) { |
| 511 | dma_buf_unmap_attachment(gem->import_attach, bo->sgt, | 512 | dma_buf_unmap_attachment_unlocked(gem->import_attach, bo->sgt, |
| 512 | DMA_TO_DEVICE); | 513 | DMA_TO_DEVICE); |
| 513 | drm_prime_gem_destroy(gem, NULL); | 514 | drm_prime_gem_destroy(gem, NULL); |
| 514 | } else { | 515 | } else { |
| 515 | tegra_bo_free(gem->dev, bo); | 516 | tegra_bo_free(gem->dev, bo); |
| @@ -1,5 +1,13 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | ||
| 3 | obj-$(CONFIG_DRM_KUNIT_TEST) += drm_format_helper_test.o drm_damage_helper_test.o \ | 3 | obj-$(CONFIG_DRM_KUNIT_TEST) += \ |
| 4 | drm_cmdline_parser_test.o drm_rect_test.o drm_format_test.o drm_plane_helper_test.o \ | 4 | drm_buddy_test.o \ |
| 5 | drm_dp_mst_helper_test.o drm_framebuffer_test.o drm_buddy_test.o drm_mm_test.o | 5 | drm_cmdline_parser_test.o \ |
| 6 | drm_damage_helper_test.o \ | ||
| 7 | drm_dp_mst_helper_test.o \ | ||
| 8 | drm_format_helper_test.o \ | ||
| 9 | drm_format_test.o \ | ||
| 10 | drm_framebuffer_test.o \ | ||
| 11 | drm_mm_test.o \ | ||
| 12 | drm_plane_helper_test.o \ | ||
| 13 | drm_rect_test.o | ||
| @@ -5,44 +5,280 @@ · 4 unmodified lines | |||
| 5 | * Copyright (c) 2022 Maíra Canal <mairacanal@riseup.net> | 5 | * Copyright (c) 2022 Maíra Canal <mairacanal@riseup.net> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #define PREFIX_STR "[drm_dp_mst_helper]" | ||
| 9 | |||
| 10 | #include <kunit/test.h> | 8 | #include <kunit/test.h> |
| 11 | 9 | ||
| 12 | #include <linux/random.h> | ||
| 13 | |||
| 14 | #include <drm/display/drm_dp_mst_helper.h> | 10 | #include <drm/display/drm_dp_mst_helper.h> |
| 15 | #include <drm/drm_print.h> | 11 | #include <drm/drm_print.h> |
| 16 | 12 | ||
| 17 | #include "../display/drm_dp_mst_topology_internal.h" | 13 | #include "../display/drm_dp_mst_topology_internal.h" |
| 18 | 14 | ||
| 15 | struct drm_dp_mst_calc_pbn_mode_test { | ||
| 16 | const int clock; | ||
| 17 | const int bpp; | ||
| 18 | const bool dsc; | ||
| 19 | const int expected; | ||
| 20 | }; | ||
| 21 | |||
| 22 | static const struct drm_dp_mst_calc_pbn_mode_test drm_dp_mst_calc_pbn_mode_cases[] = { | ||
| 23 | { | ||
| 24 | .clock = 154000, | ||
| 25 | .bpp = 30, | ||
| 26 | .dsc = false, | ||
| 27 | .expected = 689 | ||
| 28 | }, | ||
| 29 | { | ||
| 30 | .clock = 234000, | ||
| 31 | .bpp = 30, | ||
| 32 | .dsc = false, | ||
| 33 | .expected = 1047 | ||
| 34 | }, | ||
| 35 | { | ||
| 36 | .clock = 297000, | ||
| 37 | .bpp = 24, | ||
| 38 | .dsc = false, | ||
| 39 | .expected = 1063 | ||
| 40 | }, | ||
| 41 | { | ||
| 42 | .clock = 332880, | ||
| 43 | .bpp = 24, | ||
| 44 | .dsc = true, | ||
| 45 | .expected = 50 | ||
| 46 | }, | ||
| 47 | { | ||
| 48 | .clock = 324540, | ||
| 49 | .bpp = 24, | ||
| 50 | .dsc = true, | ||
| 51 | .expected = 49 | ||
| 52 | }, | ||
| 53 | }; | ||
| 54 | |||
| 19 | static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test) | 55 | static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test) |
| 20 | { | 56 | { |
| 21 | int pbn, i; | 57 | const struct drm_dp_mst_calc_pbn_mode_test *params = test->param_value; |
| 22 | const struct { | ||
| 23 | int rate; | ||
| 24 | int bpp; | ||
| 25 | int expected; | ||
| 26 | bool dsc; | ||
| 27 | } test_params[] = { | ||
| 28 | { 154000, 30, 689, false }, | ||
| 29 | { 234000, 30, 1047, false }, | ||
| 30 | { 297000, 24, 1063, false }, | ||
| 31 | { 332880, 24, 50, true }, | ||
| 32 | { 324540, 24, 49, true }, | ||
| 33 | }; | ||
| 34 | 58 | ||
| 35 | for (i = 0; i < ARRAY_SIZE(test_params); i++) { | 59 | KUNIT_EXPECT_EQ(test, drm_dp_calc_pbn_mode(params->clock, params->bpp, params->dsc), |
| 36 | pbn = drm_dp_calc_pbn_mode(test_params[i].rate, | 60 | params->expected); |
| 37 | test_params[i].bpp, | ||
| 38 | test_params[i].dsc); | ||
| 39 | KUNIT_EXPECT_EQ_MSG(test, pbn, test_params[i].expected, | ||
| 40 | "Expected PBN %d for clock %d bpp %d, got %d\n", | ||
| 41 | test_params[i].expected, test_params[i].rate, | ||
| 42 | test_params[i].bpp, pbn); | ||
| 43 | } | ||
| 44 | } | 61 | } |
| 45 | 62 | ||
| 63 | static void dp_mst_calc_pbn_mode_desc(const struct drm_dp_mst_calc_pbn_mode_test *t, char *desc) | ||
| 64 | { | ||
| 65 | sprintf(desc, "Clock %d BPP %d DSC %s", t->clock, t->bpp, t->dsc ? "enabled" : "disabled"); | ||
| 66 | } | ||
| 67 | |||
| 68 | KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_cases, | ||
| 69 | dp_mst_calc_pbn_mode_desc); | ||
| 70 | |||
| 71 | static u8 data[] = { 0xff, 0x00, 0xdd }; | ||
| 72 | |||
| 73 | struct drm_dp_mst_sideband_msg_req_test { | ||
| 74 | const char *desc; | ||
| 75 | const struct drm_dp_sideband_msg_req_body in; | ||
| 76 | }; | ||
| 77 | |||
| 78 | static const struct drm_dp_mst_sideband_msg_req_test drm_dp_mst_sideband_msg_req_cases[] = { | ||
| 79 | { | ||
| 80 | .desc = "DP_ENUM_PATH_RESOURCES with port number", | ||
| 81 | .in = { | ||
| 82 | .req_type = DP_ENUM_PATH_RESOURCES, | ||
| 83 | .u.port_num.port_number = 5, | ||
| 84 | }, | ||
| 85 | }, | ||
| 86 | { | ||
| 87 | .desc = "DP_POWER_UP_PHY with port number", | ||
| 88 | .in = { | ||
| 89 | .req_type = DP_POWER_UP_PHY, | ||
| 90 | .u.port_num.port_number = 5, | ||
| 91 | }, | ||
| 92 | }, | ||
| 93 | { | ||
| 94 | .desc = "DP_POWER_DOWN_PHY with port number", | ||
| 95 | .in = { | ||
| 96 | .req_type = DP_POWER_DOWN_PHY, | ||
| 97 | .u.port_num.port_number = 5, | ||
| 98 | }, | ||
| 99 | }, | ||
| 100 | { | ||
| 101 | .desc = "DP_ALLOCATE_PAYLOAD with SDP stream sinks", | ||
| 102 | .in = { | ||
| 103 | .req_type = DP_ALLOCATE_PAYLOAD, | ||
| 104 | .u.allocate_payload.number_sdp_streams = 3, | ||
| 105 | .u.allocate_payload.sdp_stream_sink = { 1, 2, 3 }, | ||
| 106 | }, | ||
| 107 | }, | ||
| 108 | { | ||
| 109 | .desc = "DP_ALLOCATE_PAYLOAD with port number", | ||
| 110 | .in = { | ||
| 111 | .req_type = DP_ALLOCATE_PAYLOAD, | ||
| 112 | .u.allocate_payload.port_number = 0xf, | ||
| 113 | }, | ||
| 114 | }, | ||
| 115 | { | ||
| 116 | .desc = "DP_ALLOCATE_PAYLOAD with VCPI", | ||
| 117 | .in = { | ||
| 118 | .req_type = DP_ALLOCATE_PAYLOAD, | ||
| 119 | .u.allocate_payload.vcpi = 0x7f, | ||
| 120 | }, | ||
| 121 | }, | ||
| 122 | { | ||
| 123 | .desc = "DP_ALLOCATE_PAYLOAD with PBN", | ||
| 124 | .in = { | ||
| 125 | .req_type = DP_ALLOCATE_PAYLOAD, | ||
| 126 | .u.allocate_payload.pbn = U16_MAX, | ||
| 127 | }, | ||
| 128 | }, | ||
| 129 | { | ||
| 130 | .desc = "DP_QUERY_PAYLOAD with port number", | ||
| 131 | .in = { | ||
| 132 | .req_type = DP_QUERY_PAYLOAD, | ||
| 133 | .u.query_payload.port_number = 0xf, | ||
| 134 | }, | ||
| 135 | }, | ||
| 136 | { | ||
| 137 | .desc = "DP_QUERY_PAYLOAD with VCPI", | ||
| 138 | .in = { | ||
| 139 | .req_type = DP_QUERY_PAYLOAD, | ||
| 140 | .u.query_payload.vcpi = 0x7f, | ||
| 141 | }, | ||
| 142 | }, | ||
| 143 | { | ||
| 144 | .desc = "DP_REMOTE_DPCD_READ with port number", | ||
| 145 | .in = { | ||
| 146 | .req_type = DP_REMOTE_DPCD_READ, | ||
| 147 | .u.dpcd_read.port_number = 0xf, | ||
| 148 | }, | ||
| 149 | }, | ||
| 150 | { | ||
| 151 | .desc = "DP_REMOTE_DPCD_READ with DPCD address", | ||
| 152 | .in = { | ||
| 153 | .req_type = DP_REMOTE_DPCD_READ, | ||
| 154 | .u.dpcd_read.dpcd_address = 0xfedcb, | ||
| 155 | }, | ||
| 156 | }, | ||
| 157 | { | ||
| 158 | .desc = "DP_REMOTE_DPCD_READ with max number of bytes", | ||
| 159 | .in = { | ||
| 160 | .req_type = DP_REMOTE_DPCD_READ, | ||
| 161 | .u.dpcd_read.num_bytes = U8_MAX, | ||
| 162 | }, | ||
| 163 | }, | ||
| 164 | { | ||
| 165 | .desc = "DP_REMOTE_DPCD_WRITE with port number", | ||
| 166 | .in = { | ||
| 167 | .req_type = DP_REMOTE_DPCD_WRITE, | ||
| 168 | .u.dpcd_write.port_number = 0xf, | ||
| 169 | }, | ||
| 170 | }, | ||
| 171 | { | ||
| 172 | .desc = "DP_REMOTE_DPCD_WRITE with DPCD address", | ||
| 173 | .in = { | ||
| 174 | .req_type = DP_REMOTE_DPCD_WRITE, | ||
| 175 | .u.dpcd_write.dpcd_address = 0xfedcb, | ||
| 176 | }, | ||
| 177 | }, | ||
| 178 | { | ||
| 179 | .desc = "DP_REMOTE_DPCD_WRITE with data array", | ||
| 180 | .in = { | ||
| 181 | .req_type = DP_REMOTE_DPCD_WRITE, | ||
| 182 | .u.dpcd_write.num_bytes = ARRAY_SIZE(data), | ||
| 183 | .u.dpcd_write.bytes = data, | ||
| 184 | }, | ||
| 185 | }, | ||
| 186 | { | ||
| 187 | .desc = "DP_REMOTE_I2C_READ with port number", | ||
| 188 | .in = { | ||
| 189 | .req_type = DP_REMOTE_I2C_READ, | ||
| 190 | .u.i2c_read.port_number = 0xf, | ||
| 191 | }, | ||
| 192 | }, | ||
| 193 | { | ||
| 194 | .desc = "DP_REMOTE_I2C_READ with I2C device ID", | ||
| 195 | .in = { | ||
| 196 | .req_type = DP_REMOTE_I2C_READ, | ||
| 197 | .u.i2c_read.read_i2c_device_id = 0x7f, | ||
| 198 | }, | ||
| 199 | }, | ||
| 200 | { | ||
| 201 | .desc = "DP_REMOTE_I2C_READ with transactions array", | ||
| 202 | .in = { | ||
| 203 | .req_type = DP_REMOTE_I2C_READ, | ||
| 204 | .u.i2c_read.num_transactions = 3, | ||
| 205 | .u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3, | ||
| 206 | .u.i2c_read.transactions = { | ||
| 207 | { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7f, | ||
| 208 | .i2c_transaction_delay = 0xf, }, | ||
| 209 | { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7e, | ||
| 210 | .i2c_transaction_delay = 0xe, }, | ||
| 211 | { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7d, | ||
| 212 | .i2c_transaction_delay = 0xd, }, | ||
| 213 | }, | ||
| 214 | }, | ||
| 215 | }, | ||
| 216 | { | ||
| 217 | .desc = "DP_REMOTE_I2C_WRITE with port number", | ||
| 218 | .in = { | ||
| 219 | .req_type = DP_REMOTE_I2C_WRITE, | ||
| 220 | .u.i2c_write.port_number = 0xf, | ||
| 221 | }, | ||
| 222 | }, | ||
| 223 | { | ||
| 224 | .desc = "DP_REMOTE_I2C_WRITE with I2C device ID", | ||
| 225 | .in = { | ||
| 226 | .req_type = DP_REMOTE_I2C_WRITE, | ||
| 227 | .u.i2c_write.write_i2c_device_id = 0x7f, | ||
| 228 | }, | ||
| 229 | }, | ||
| 230 | { | ||
| 231 | .desc = "DP_REMOTE_I2C_WRITE with data array", | ||
| 232 | .in = { | ||
| 233 | .req_type = DP_REMOTE_I2C_WRITE, | ||
| 234 | .u.i2c_write.num_bytes = ARRAY_SIZE(data), | ||
| 235 | .u.i2c_write.bytes = data, | ||
| 236 | }, | ||
| 237 | }, | ||
| 238 | { | ||
| 239 | .desc = "DP_QUERY_STREAM_ENC_STATUS with stream ID", | ||
| 240 | .in = { | ||
| 241 | .req_type = DP_QUERY_STREAM_ENC_STATUS, | ||
| 242 | .u.enc_status.stream_id = 1, | ||
| 243 | }, | ||
| 244 | }, | ||
| 245 | { | ||
| 246 | .desc = "DP_QUERY_STREAM_ENC_STATUS with client ID", | ||
| 247 | .in = { | ||
| 248 | .req_type = DP_QUERY_STREAM_ENC_STATUS, | ||
| 249 | .u.enc_status.client_id = { 0x4f, 0x7f, 0xb4, 0x00, 0x8c, 0x0d, 0x67 }, | ||
| 250 | }, | ||
| 251 | }, | ||
| 252 | { | ||
| 253 | .desc = "DP_QUERY_STREAM_ENC_STATUS with stream event", | ||
| 254 | .in = { | ||
| 255 | .req_type = DP_QUERY_STREAM_ENC_STATUS, | ||
| 256 | .u.enc_status.stream_event = 3, | ||
| 257 | }, | ||
| 258 | }, | ||
| 259 | { | ||
| 260 | .desc = "DP_QUERY_STREAM_ENC_STATUS with valid stream event", | ||
| 261 | .in = { | ||
| 262 | .req_type = DP_QUERY_STREAM_ENC_STATUS, | ||
| 263 | .u.enc_status.valid_stream_event = 0, | ||
| 264 | }, | ||
| 265 | }, | ||
| 266 | { | ||
| 267 | .desc = "DP_QUERY_STREAM_ENC_STATUS with stream behavior", | ||
| 268 | .in = { | ||
| 269 | .req_type = DP_QUERY_STREAM_ENC_STATUS, | ||
| 270 | .u.enc_status.stream_behavior = 3, | ||
| 271 | }, | ||
| 272 | }, | ||
| 273 | { | ||
| 274 | .desc = "DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior", | ||
| 275 | .in = { | ||
| 276 | .req_type = DP_QUERY_STREAM_ENC_STATUS, | ||
| 277 | .u.enc_status.valid_stream_behavior = 1, | ||
| 278 | } | ||
| 279 | }, | ||
| 280 | }; | ||
| 281 | |||
| 46 | static bool | 282 | static bool |
| 47 | sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in, | 283 | sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in, |
| 48 | const struct drm_dp_sideband_msg_req_body *out) | 284 | const struct drm_dp_sideband_msg_req_body *out) |
| @@ -118,41 +354,41 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in, · 69 unmodified lines | |||
| 118 | return true; | 354 | return true; |
| 119 | } | 355 | } |
| 120 | 356 | ||
| 121 | static bool | 357 | static void drm_test_dp_mst_msg_printf(struct drm_printer *p, struct va_format *vaf) |
| 122 | sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in) | ||
| 123 | { | 358 | { |
| 359 | struct kunit *test = p->arg; | ||
| 360 | |||
| 361 | kunit_err(test, "%pV", vaf); | ||
| 362 | } | ||
| 363 | |||
| 364 | static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test) | ||
| 365 | { | ||
| 366 | const struct drm_dp_mst_sideband_msg_req_test *params = test->param_value; | ||
| 367 | const struct drm_dp_sideband_msg_req_body *in = ¶ms->in; | ||
| 124 | struct drm_dp_sideband_msg_req_body *out; | 368 | struct drm_dp_sideband_msg_req_body *out; |
| 125 | struct drm_printer p = drm_err_printer(PREFIX_STR); | ||
| 126 | struct drm_dp_sideband_msg_tx *txmsg; | 369 | struct drm_dp_sideband_msg_tx *txmsg; |
| 127 | int i, ret; | 370 | struct drm_printer p = { |
| 128 | bool result = true; | 371 | .printfn = drm_test_dp_mst_msg_printf, |
| 372 | .arg = test | ||
| 373 | }; | ||
| 374 | int i; | ||
| 129 | 375 | ||
| 130 | out = kzalloc(sizeof(*out), GFP_KERNEL); | 376 | out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL); |
| 131 | if (!out) | 377 | KUNIT_ASSERT_NOT_NULL(test, out); |
| 132 | return false; | ||
| 133 | 378 | ||
| 134 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); | 379 | txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL); |
| 135 | if (!txmsg) { | 380 | KUNIT_ASSERT_NOT_NULL(test, txmsg); |
| 136 | kfree(out); | ||
| 137 | return false; | ||
| 138 | } | ||
| 139 | 381 | ||
| 140 | drm_dp_encode_sideband_req(in, txmsg); | 382 | drm_dp_encode_sideband_req(in, txmsg); |
| 141 | ret = drm_dp_decode_sideband_req(txmsg, out); | 383 | KUNIT_EXPECT_GE_MSG(test, drm_dp_decode_sideband_req(txmsg, out), 0, |
| 142 | if (ret < 0) { | 384 | "Failed to decode sideband request"); |
| 143 | drm_printf(&p, "Failed to decode sideband request: %d\n", | ||
| 144 | ret); | ||
| 145 | result = false; | ||
| 146 | goto out; | ||
| 147 | } | ||
| 148 | 385 | ||
| 149 | if (!sideband_msg_req_equal(in, out)) { | 386 | if (!sideband_msg_req_equal(in, out)) { |
| 150 | drm_printf(&p, "Encode/decode failed, expected:\n"); | 387 | KUNIT_FAIL(test, "Encode/decode failed"); |
| 388 | kunit_err(test, "Expected:"); | ||
| 151 | drm_dp_dump_sideband_msg_req_body(in, 1, &p); | 389 | drm_dp_dump_sideband_msg_req_body(in, 1, &p); |
| 152 | drm_printf(&p, "Got:\n"); | 390 | kunit_err(test, "Got:"); |
| 153 | drm_dp_dump_sideband_msg_req_body(out, 1, &p); | 391 | drm_dp_dump_sideband_msg_req_body(out, 1, &p); |
| 154 | result = false; | ||
| 155 | goto out; | ||
| 156 | } | 392 | } |
| 157 | 393 | ||
| 158 | switch (in->req_type) { | 394 | switch (in->req_type) { |
| @@ -167,112 +403,21 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in) · 8 unmodified lines | |||
| 167 | kfree(out->u.i2c_write.bytes); | 403 | kfree(out->u.i2c_write.bytes); |
| 168 | break; | 404 | break; |
| 169 | } | 405 | } |
| 170 | |||
| 171 | /* Clear everything but the req_type for the input */ | ||
| 172 | memset(&in->u, 0, sizeof(in->u)); | ||
| 173 | |||
| 174 | out: | ||
| 175 | kfree(out); | ||
| 176 | kfree(txmsg); | ||
| 177 | return result; | ||
| 178 | } | 406 | } |
| 179 | 407 | ||
| 180 | static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test) | 408 | static void |
| 409 | drm_dp_mst_sideband_msg_req_desc(const struct drm_dp_mst_sideband_msg_req_test *t, char *desc) | ||
| 181 | { | 410 | { |
| 182 | struct drm_dp_sideband_msg_req_body in = { 0 }; | 411 | strcpy(desc, t->desc); |
| 183 | u8 data[] = { 0xff, 0x0, 0xdd }; | ||
| 184 | int i; | ||
| 185 | |||
| 186 | in.req_type = DP_ENUM_PATH_RESOURCES; | ||
| 187 | in.u.port_num.port_number = 5; | ||
| 188 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 189 | |||
| 190 | in.req_type = DP_POWER_UP_PHY; | ||
| 191 | in.u.port_num.port_number = 5; | ||
| 192 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 193 | |||
| 194 | in.req_type = DP_POWER_DOWN_PHY; | ||
| 195 | in.u.port_num.port_number = 5; | ||
| 196 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 197 | |||
| 198 | in.req_type = DP_ALLOCATE_PAYLOAD; | ||
| 199 | in.u.allocate_payload.number_sdp_streams = 3; | ||
| 200 | for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++) | ||
| 201 | in.u.allocate_payload.sdp_stream_sink[i] = i + 1; | ||
| 202 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 203 | in.u.allocate_payload.port_number = 0xf; | ||
| 204 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 205 | in.u.allocate_payload.vcpi = 0x7f; | ||
| 206 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 207 | in.u.allocate_payload.pbn = U16_MAX; | ||
| 208 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 209 | |||
| 210 | in.req_type = DP_QUERY_PAYLOAD; | ||
| 211 | in.u.query_payload.port_number = 0xf; | ||
| 212 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 213 | in.u.query_payload.vcpi = 0x7f; | ||
| 214 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 215 | |||
| 216 | in.req_type = DP_REMOTE_DPCD_READ; | ||
| 217 | in.u.dpcd_read.port_number = 0xf; | ||
| 218 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 219 | in.u.dpcd_read.dpcd_address = 0xfedcb; | ||
| 220 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 221 | in.u.dpcd_read.num_bytes = U8_MAX; | ||
| 222 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 223 | |||
| 224 | in.req_type = DP_REMOTE_DPCD_WRITE; | ||
| 225 | in.u.dpcd_write.port_number = 0xf; | ||
| 226 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 227 | in.u.dpcd_write.dpcd_address = 0xfedcb; | ||
| 228 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 229 | in.u.dpcd_write.num_bytes = ARRAY_SIZE(data); | ||
| 230 | in.u.dpcd_write.bytes = data; | ||
| 231 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 232 | |||
| 233 | in.req_type = DP_REMOTE_I2C_READ; | ||
| 234 | in.u.i2c_read.port_number = 0xf; | ||
| 235 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 236 | in.u.i2c_read.read_i2c_device_id = 0x7f; | ||
| 237 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 238 | in.u.i2c_read.num_transactions = 3; | ||
| 239 | in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3; | ||
| 240 | for (i = 0; i < in.u.i2c_read.num_transactions; i++) { | ||
| 241 | in.u.i2c_read.transactions[i].bytes = data; | ||
| 242 | in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data); | ||
| 243 | in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i; | ||
| 244 | in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i; | ||
| 245 | } | ||
| 246 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 247 | |||
| 248 | in.req_type = DP_REMOTE_I2C_WRITE; | ||
| 249 | in.u.i2c_write.port_number = 0xf; | ||
| 250 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 251 | in.u.i2c_write.write_i2c_device_id = 0x7f; | ||
| 252 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 253 | in.u.i2c_write.num_bytes = ARRAY_SIZE(data); | ||
| 254 | in.u.i2c_write.bytes = data; | ||
| 255 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 256 | |||
| 257 | in.req_type = DP_QUERY_STREAM_ENC_STATUS; | ||
| 258 | in.u.enc_status.stream_id = 1; | ||
| 259 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 260 | get_random_bytes(in.u.enc_status.client_id, | ||
| 261 | sizeof(in.u.enc_status.client_id)); | ||
| 262 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 263 | in.u.enc_status.stream_event = 3; | ||
| 264 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 265 | in.u.enc_status.valid_stream_event = 0; | ||
| 266 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 267 | in.u.enc_status.stream_behavior = 3; | ||
| 268 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 269 | in.u.enc_status.valid_stream_behavior = 1; | ||
| 270 | KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); | ||
| 271 | } | 412 | } |
| 272 | 413 | ||
| 414 | KUNIT_ARRAY_PARAM(drm_dp_mst_sideband_msg_req, drm_dp_mst_sideband_msg_req_cases, | ||
| 415 | drm_dp_mst_sideband_msg_req_desc); | ||
| 416 | |||
| 273 | static struct kunit_case drm_dp_mst_helper_tests[] = { | 417 | static struct kunit_case drm_dp_mst_helper_tests[] = { |
| 274 | KUNIT_CASE(drm_test_dp_mst_calc_pbn_mode), | 418 | KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_gen_params), |
| 275 | KUNIT_CASE(drm_test_dp_mst_sideband_msg_req_decode), | 419 | KUNIT_CASE_PARAM(drm_test_dp_mst_sideband_msg_req_decode, |
| 420 | drm_dp_mst_sideband_msg_req_gen_params), | ||
| 276 | { } | 421 | { } |
| 277 | }; | 422 | }; |
| 278 | 423 | ||
| @@ -51,6 +51,19 @@ config DRM_GM12U320 · 50 unmodified lines | |||
| 51 | This is a KMS driver for projectors which use the GM12U320 chipset | 51 | This is a KMS driver for projectors which use the GM12U320 chipset |
| 52 | for video transfer over USB2/3, such as the Acer C120 mini projector. | 52 | for video transfer over USB2/3, such as the Acer C120 mini projector. |
| 53 | 53 | ||
| 54 | config DRM_OFDRM | ||
| 55 | tristate "Open Firmware display driver" | ||
| 56 | depends on DRM && OF && (PPC || COMPILE_TEST) | ||
| 57 | select APERTURE_HELPERS | ||
| 58 | select DRM_GEM_SHMEM_HELPER | ||
| 59 | select DRM_KMS_HELPER | ||
| 60 | help | ||
| 61 | DRM driver for Open Firmware framebuffers. | ||
| 62 | |||
| 63 | This driver assumes that the display hardware has been initialized | ||
| 64 | by the Open Firmware before the kernel boots. Scanout buffer, size, | ||
| 65 | and display format must be provided via device tree. | ||
| 66 | |||
| 54 | config DRM_PANEL_MIPI_DBI | 67 | config DRM_PANEL_MIPI_DBI |
| 55 | tristate "DRM support for MIPI DBI compatible panels" | 68 | tristate "DRM support for MIPI DBI compatible panels" |
| 56 | depends on DRM && SPI | 69 | depends on DRM && SPI |
| @@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o · 3 unmodified lines | |||
| 4 | obj-$(CONFIG_DRM_BOCHS) += bochs.o | 4 | obj-$(CONFIG_DRM_BOCHS) += bochs.o |
| 5 | obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o | 5 | obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o |
| 6 | obj-$(CONFIG_DRM_GM12U320) += gm12u320.o | 6 | obj-$(CONFIG_DRM_GM12U320) += gm12u320.o |
| 7 | obj-$(CONFIG_DRM_OFDRM) += ofdrm.o | ||
| 7 | obj-$(CONFIG_DRM_PANEL_MIPI_DBI) += panel-mipi-dbi.o | 8 | obj-$(CONFIG_DRM_PANEL_MIPI_DBI) += panel-mipi-dbi.o |
| 8 | obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o | 9 | obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o |
| 9 | obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o | 10 | obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o |
| @@ -543,7 +543,6 @@ static int bochs_kms_init(struct bochs_device *bochs) · 542 unmodified lines | |||
| 543 | bochs->dev->mode_config.max_width = 8192; | 543 | bochs->dev->mode_config.max_width = 8192; |
| 544 | bochs->dev->mode_config.max_height = 8192; | 544 | bochs->dev->mode_config.max_height = 8192; |
| 545 | 545 | ||
| 546 | bochs->dev->mode_config.fb_base = bochs->fb_base; | ||
| 547 | bochs->dev->mode_config.preferred_depth = 24; | 546 | bochs->dev->mode_config.preferred_depth = 24; |
| 548 | bochs->dev->mode_config.prefer_shadow = 0; | 547 | bochs->dev->mode_config.prefer_shadow = 0; |
| 549 | bochs->dev->mode_config.prefer_shadow_fbdev = 1; | 548 | bochs->dev->mode_config.prefer_shadow_fbdev = 1; |
| @@ -0,0 +1,1424 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | |||
| 3 | #include <linux/of_address.h> | ||
| 4 | #include <linux/pci.h> | ||
| 5 | #include <linux/platform_device.h> | ||
| 6 | |||
| 7 | #include <drm/drm_aperture.h> | ||
| 8 | #include <drm/drm_atomic.h> | ||
| 9 | #include <drm/drm_atomic_state_helper.h> | ||
| 10 | #include <drm/drm_connector.h> | ||
| 11 | #include <drm/drm_damage_helper.h> | ||
| 12 | #include <drm/drm_device.h> | ||
| 13 | #include <drm/drm_drv.h> | ||
| 14 | #include <drm/drm_fb_helper.h> | ||
| 15 | #include <drm/drm_format_helper.h> | ||
| 16 | #include <drm/drm_framebuffer.h> | ||
| 17 | #include <drm/drm_gem_atomic_helper.h> | ||
| 18 | #include <drm/drm_gem_framebuffer_helper.h> | ||
| 19 | #include <drm/drm_gem_shmem_helper.h> | ||
| 20 | #include <drm/drm_managed.h> | ||
| 21 | #include <drm/drm_modeset_helper_vtables.h> | ||
| 22 | #include <drm/drm_plane_helper.h> | ||
| 23 | #include <drm/drm_probe_helper.h> | ||
| 24 | #include <drm/drm_simple_kms_helper.h> | ||
| 25 | |||
| 26 | #define DRIVER_NAME "ofdrm" | ||
| 27 | #define DRIVER_DESC "DRM driver for OF platform devices" | ||
| 28 | #define DRIVER_DATE "20220501" | ||
| 29 | #define DRIVER_MAJOR 1 | ||
| 30 | #define DRIVER_MINOR 0 | ||
| 31 | |||
| 32 | #define PCI_VENDOR_ID_ATI_R520 0x7100 | ||
| 33 | #define PCI_VENDOR_ID_ATI_R600 0x9400 | ||
| 34 | |||
| 35 | #define OFDRM_GAMMA_LUT_SIZE 256 | ||
| 36 | |||
| 37 | /* Definitions used by the Avivo palette */ | ||
| 38 | #define AVIVO_DC_LUT_RW_SELECT 0x6480 | ||
| 39 | #define AVIVO_DC_LUT_RW_MODE 0x6484 | ||
| 40 | #define AVIVO_DC_LUT_RW_INDEX 0x6488 | ||
| 41 | #define AVIVO_DC_LUT_SEQ_COLOR 0x648c | ||
| 42 | #define AVIVO_DC_LUT_PWL_DATA 0x6490 | ||
| 43 | #define AVIVO_DC_LUT_30_COLOR 0x6494 | ||
| 44 | #define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498 | ||
| 45 | #define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c | ||
| 46 | #define AVIVO_DC_LUT_AUTOFILL 0x64a0 | ||
| 47 | #define AVIVO_DC_LUTA_CONTROL 0x64c0 | ||
| 48 | #define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4 | ||
| 49 | #define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8 | ||
| 50 | #define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc | ||
| 51 | #define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0 | ||
| 52 | #define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 | ||
| 53 | #define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 | ||
| 54 | #define AVIVO_DC_LUTB_CONTROL 0x6cc0 | ||
| 55 | #define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4 | ||
| 56 | #define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8 | ||
| 57 | #define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc | ||
| 58 | #define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0 | ||
| 59 | #define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4 | ||
| 60 | #define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8 | ||
| 61 | |||
| 62 | enum ofdrm_model { | ||
| 63 | OFDRM_MODEL_UNKNOWN, | ||
| 64 | OFDRM_MODEL_MACH64, /* ATI Mach64 */ | ||
| 65 | OFDRM_MODEL_RAGE128, /* ATI Rage128 */ | ||
| 66 | OFDRM_MODEL_RAGE_M3A, /* ATI Rage Mobility M3 Head A */ | ||
| 67 | OFDRM_MODEL_RAGE_M3B, /* ATI Rage Mobility M3 Head B */ | ||
| 68 | OFDRM_MODEL_RADEON, /* ATI Radeon */ | ||
| 69 | OFDRM_MODEL_GXT2000, /* IBM GXT2000 */ | ||
| 70 | OFDRM_MODEL_AVIVO, /* ATI R5xx */ | ||
| 71 | OFDRM_MODEL_QEMU, /* QEMU VGA */ | ||
| 72 | }; | ||
| 73 | |||
| 74 | /* | ||
| 75 | * Helpers for display nodes | ||
| 76 | */ | ||
| 77 | |||
| 78 | static int display_get_validated_int(struct drm_device *dev, const char *name, uint32_t value) | ||
| 79 | { | ||
| 80 | if (value > INT_MAX) { | ||
| 81 | drm_err(dev, "invalid framebuffer %s of %u\n", name, value); | ||
| 82 | return -EINVAL; | ||
| 83 | } | ||
| 84 | return (int)value; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int display_get_validated_int0(struct drm_device *dev, const char *name, uint32_t value) | ||
| 88 | { | ||
| 89 | if (!value) { | ||
| 90 | drm_err(dev, "invalid framebuffer %s of %u\n", name, value); | ||
| 91 | return -EINVAL; | ||
| 92 | } | ||
| 93 | return display_get_validated_int(dev, name, value); | ||
| 94 | } | ||
| 95 | |||
| 96 | static const struct drm_format_info *display_get_validated_format(struct drm_device *dev, | ||
| 97 | u32 depth, bool big_endian) | ||
| 98 | { | ||
| 99 | const struct drm_format_info *info; | ||
| 100 | u32 format; | ||
| 101 | |||
| 102 | switch (depth) { | ||
| 103 | case 8: | ||
| 104 | format = drm_mode_legacy_fb_format(8, 8); | ||
| 105 | break; | ||
| 106 | case 15: | ||
| 107 | case 16: | ||
| 108 | format = drm_mode_legacy_fb_format(16, depth); | ||
| 109 | break; | ||
| 110 | case 32: | ||
| 111 | format = drm_mode_legacy_fb_format(32, 24); | ||
| 112 | break; | ||
| 113 | default: | ||
| 114 | drm_err(dev, "unsupported framebuffer depth %u\n", depth); | ||
| 115 | return ERR_PTR(-EINVAL); | ||
| 116 | } | ||
| 117 | |||
| 118 | /* | ||
| 119 | * DRM formats assume little-endian byte order. Update the format | ||
| 120 | * if the scanout buffer uses big-endian ordering. | ||
| 121 | */ | ||
| 122 | if (big_endian) { | ||
| 123 | switch (format) { | ||
| 124 | case DRM_FORMAT_XRGB8888: | ||
| 125 | format = DRM_FORMAT_BGRX8888; | ||
| 126 | break; | ||
| 127 | case DRM_FORMAT_ARGB8888: | ||
| 128 | format = DRM_FORMAT_BGRA8888; | ||
| 129 | break; | ||
| 130 | case DRM_FORMAT_RGB565: | ||
| 131 | format = DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN; | ||
| 132 | break; | ||
| 133 | case DRM_FORMAT_XRGB1555: | ||
| 134 | format = DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN; | ||
| 135 | break; | ||
| 136 | default: | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | info = drm_format_info(format); | ||
| 142 | if (!info) { | ||
| 143 | drm_err(dev, "cannot find framebuffer format for depth %u\n", depth); | ||
| 144 | return ERR_PTR(-EINVAL); | ||
| 145 | } | ||
| 146 | |||
| 147 | return info; | ||
| 148 | } | ||
| 149 | |||
| 150 | static int display_read_u32_of(struct drm_device *dev, struct device_node *of_node, | ||
| 151 | const char *name, u32 *value) | ||
| 152 | { | ||
| 153 | int ret = of_property_read_u32(of_node, name, value); | ||
| 154 | |||
| 155 | if (ret) | ||
| 156 | drm_err(dev, "cannot parse framebuffer %s: error %d\n", name, ret); | ||
| 157 | return ret; | ||
| 158 | } | ||
| 159 | |||
| 160 | static bool display_get_big_endian_of(struct drm_device *dev, struct device_node *of_node) | ||
| 161 | { | ||
| 162 | bool big_endian; | ||
| 163 | |||
| 164 | #ifdef __BIG_ENDIAN | ||
| 165 | big_endian = true; | ||
| 166 | if (of_get_property(of_node, "little-endian", NULL)) | ||
| 167 | big_endian = false; | ||
| 168 | #else | ||
| 169 | big_endian = false; | ||
| 170 | if (of_get_property(of_node, "big-endian", NULL)) | ||
| 171 | big_endian = true; | ||
| 172 | #endif | ||
| 173 | |||
| 174 | return big_endian; | ||
| 175 | } | ||
| 176 | |||
| 177 | static int display_get_width_of(struct drm_device *dev, struct device_node *of_node) | ||
| 178 | { | ||
| 179 | u32 width; | ||
| 180 | int ret = display_read_u32_of(dev, of_node, "width", &width); | ||
| 181 | |||
| 182 | if (ret) | ||
| 183 | return ret; | ||
| 184 | return display_get_validated_int0(dev, "width", width); | ||
| 185 | } | ||
| 186 | |||
| 187 | static int display_get_height_of(struct drm_device *dev, struct device_node *of_node) | ||
| 188 | { | ||
| 189 | u32 height; | ||
| 190 | int ret = display_read_u32_of(dev, of_node, "height", &height); | ||
| 191 | |||
| 192 | if (ret) | ||
| 193 | return ret; | ||
| 194 | return display_get_validated_int0(dev, "height", height); | ||
| 195 | } | ||
| 196 | |||
| 197 | static int display_get_depth_of(struct drm_device *dev, struct device_node *of_node) | ||
| 198 | { | ||
| 199 | u32 depth; | ||
| 200 | int ret = display_read_u32_of(dev, of_node, "depth", &depth); | ||
| 201 | |||
| 202 | if (ret) | ||
| 203 | return ret; | ||
| 204 | return display_get_validated_int0(dev, "depth", depth); | ||
| 205 | } | ||
| 206 | |||
| 207 | static int display_get_linebytes_of(struct drm_device *dev, struct device_node *of_node) | ||
| 208 | { | ||
| 209 | u32 linebytes; | ||
| 210 | int ret = display_read_u32_of(dev, of_node, "linebytes", &linebytes); | ||
| 211 | |||
| 212 | if (ret) | ||
| 213 | return ret; | ||
| 214 | return display_get_validated_int(dev, "linebytes", linebytes); | ||
| 215 | } | ||
| 216 | |||
| 217 | static u64 display_get_address_of(struct drm_device *dev, struct device_node *of_node) | ||
| 218 | { | ||
| 219 | u32 address; | ||
| 220 | int ret; | ||
| 221 | |||
| 222 | /* | ||
| 223 | * Not all devices provide an address property, it's not | ||
| 224 | * a bug if this fails. The driver will try to find the | ||
| 225 | * framebuffer base address from the device's memory regions. | ||
| 226 | */ | ||
| 227 | ret = of_property_read_u32(of_node, "address", &address); | ||
| 228 | if (ret) | ||
| 229 | return OF_BAD_ADDR; | ||
| 230 | |||
| 231 | return address; | ||
| 232 | } | ||
| 233 | |||
| 234 | static bool is_avivo(__be32 vendor, __be32 device) | ||
| 235 | { | ||
| 236 | /* This will match most R5xx */ | ||
| 237 | return (vendor == PCI_VENDOR_ID_ATI) && | ||
| 238 | ((device >= PCI_VENDOR_ID_ATI_R520 && device < 0x7800) || | ||
| 239 | (PCI_VENDOR_ID_ATI_R600 >= 0x9400)); | ||
| 240 | } | ||
| 241 | |||
| 242 | static enum ofdrm_model display_get_model_of(struct drm_device *dev, struct device_node *of_node) | ||
| 243 | { | ||
| 244 | enum ofdrm_model model = OFDRM_MODEL_UNKNOWN; | ||
| 245 | |||
| 246 | if (of_node_name_prefix(of_node, "ATY,Rage128")) { | ||
| 247 | model = OFDRM_MODEL_RAGE128; | ||
| 248 | } else if (of_node_name_prefix(of_node, "ATY,RageM3pA") || | ||
| 249 | of_node_name_prefix(of_node, "ATY,RageM3p12A")) { | ||
| 250 | model = OFDRM_MODEL_RAGE_M3A; | ||
| 251 | } else if (of_node_name_prefix(of_node, "ATY,RageM3pB")) { | ||
| 252 | model = OFDRM_MODEL_RAGE_M3B; | ||
| 253 | } else if (of_node_name_prefix(of_node, "ATY,Rage6")) { | ||
| 254 | model = OFDRM_MODEL_RADEON; | ||
| 255 | } else if (of_node_name_prefix(of_node, "ATY,")) { | ||
| 256 | return OFDRM_MODEL_MACH64; | ||
| 257 | } else if (of_device_is_compatible(of_node, "pci1014,b7") || | ||
| 258 | of_device_is_compatible(of_node, "pci1014,21c")) { | ||
| 259 | model = OFDRM_MODEL_GXT2000; | ||
| 260 | } else if (of_node_name_prefix(of_node, "vga,Display-")) { | ||
| 261 | struct device_node *of_parent; | ||
| 262 | const __be32 *vendor_p, *device_p; | ||
| 263 | |||
| 264 | /* Look for AVIVO initialized by SLOF */ | ||
| 265 | of_parent = of_get_parent(of_node); | ||
| 266 | vendor_p = of_get_property(of_parent, "vendor-id", NULL); | ||
| 267 | device_p = of_get_property(of_parent, "device-id", NULL); | ||
| 268 | if (vendor_p && device_p && is_avivo(*vendor_p, *device_p)) | ||
| 269 | model = OFDRM_MODEL_AVIVO; | ||
| 270 | of_node_put(of_parent); | ||
| 271 | } else if (of_device_is_compatible(of_node, "qemu,std-vga")) { | ||
| 272 | model = OFDRM_MODEL_QEMU; | ||
| 273 | } | ||
| 274 | |||
| 275 | return model; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* | ||
| 279 | * Open Firmware display device | ||
| 280 | */ | ||
| 281 | |||
| 282 | struct ofdrm_device; | ||
| 283 | |||
| 284 | struct ofdrm_device_funcs { | ||
| 285 | void __iomem *(*cmap_ioremap)(struct ofdrm_device *odev, | ||
| 286 | struct device_node *of_node, | ||
| 287 | u64 fb_bas); | ||
| 288 | void (*cmap_write)(struct ofdrm_device *odev, unsigned char index, | ||
| 289 | unsigned char r, unsigned char g, unsigned char b); | ||
| 290 | }; | ||
| 291 | |||
| 292 | struct ofdrm_device { | ||
| 293 | struct drm_device dev; | ||
| 294 | struct platform_device *pdev; | ||
| 295 | |||
| 296 | const struct ofdrm_device_funcs *funcs; | ||
| 297 | |||
| 298 | /* firmware-buffer settings */ | ||
| 299 | struct iosys_map screen_base; | ||
| 300 | struct drm_display_mode mode; | ||
| 301 | const struct drm_format_info *format; | ||
| 302 | unsigned int pitch; | ||
| 303 | |||
| 304 | /* colormap */ | ||
| 305 | void __iomem *cmap_base; | ||
| 306 | |||
| 307 | /* modesetting */ | ||
| 308 | uint32_t formats[8]; | ||
| 309 | struct drm_plane primary_plane; | ||
| 310 | struct drm_crtc crtc; | ||
| 311 | struct drm_encoder encoder; | ||
| 312 | struct drm_connector connector; | ||
| 313 | }; | ||
| 314 | |||
| 315 | static struct ofdrm_device *ofdrm_device_of_dev(struct drm_device *dev) | ||
| 316 | { | ||
| 317 | return container_of(dev, struct ofdrm_device, dev); | ||
| 318 | } | ||
| 319 | |||
| 320 | /* | ||
| 321 | * Hardware | ||
| 322 | */ | ||
| 323 | |||
| 324 | #if defined(CONFIG_PCI) | ||
| 325 | static struct pci_dev *display_get_pci_dev_of(struct drm_device *dev, struct device_node *of_node) | ||
| 326 | { | ||
| 327 | const __be32 *vendor_p, *device_p; | ||
| 328 | u32 vendor, device; | ||
| 329 | struct pci_dev *pcidev; | ||
| 330 | |||
| 331 | vendor_p = of_get_property(of_node, "vendor-id", NULL); | ||
| 332 | if (!vendor_p) | ||
| 333 | return ERR_PTR(-ENODEV); | ||
| 334 | vendor = be32_to_cpup(vendor_p); | ||
| 335 | |||
| 336 | device_p = of_get_property(of_node, "device-id", NULL); | ||
| 337 | if (!device_p) | ||
| 338 | return ERR_PTR(-ENODEV); | ||
| 339 | device = be32_to_cpup(device_p); | ||
| 340 | |||
| 341 | pcidev = pci_get_device(vendor, device, NULL); | ||
| 342 | if (!pcidev) | ||
| 343 | return ERR_PTR(-ENODEV); | ||
| 344 | |||
| 345 | return pcidev; | ||
| 346 | } | ||
| 347 | |||
| 348 | static void ofdrm_pci_release(void *data) | ||
| 349 | { | ||
| 350 | struct pci_dev *pcidev = data; | ||
| 351 | |||
| 352 | pci_disable_device(pcidev); | ||
| 353 | } | ||
| 354 | |||
| 355 | static int ofdrm_device_init_pci(struct ofdrm_device *odev) | ||
| 356 | { | ||
| 357 | struct drm_device *dev = &odev->dev; | ||
| 358 | struct platform_device *pdev = to_platform_device(dev->dev); | ||
| 359 | struct device_node *of_node = pdev->dev.of_node; | ||
| 360 | struct pci_dev *pcidev; | ||
| 361 | int ret; | ||
| 362 | |||
| 363 | /* | ||
| 364 | * Never use pcim_ or other managed helpers on the returned PCI | ||
| 365 | * device. Otherwise, probing the native driver will fail for | ||
| 366 | * resource conflicts. PCI-device management has to be tied to | ||
| 367 | * the lifetime of the platform device until the native driver | ||
| 368 | * takes over. | ||
| 369 | */ | ||
| 370 | pcidev = display_get_pci_dev_of(dev, of_node); | ||
| 371 | if (IS_ERR(pcidev)) | ||
| 372 | return 0; /* no PCI device found; ignore the error */ | ||
| 373 | |||
| 374 | ret = pci_enable_device(pcidev); | ||
| 375 | if (ret) { | ||
| 376 | drm_err(dev, "pci_enable_device(%s) failed: %d\n", | ||
| 377 | dev_name(&pcidev->dev), ret); | ||
| 378 | return ret; | ||
| 379 | } | ||
| 380 | ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); | ||
| 381 | if (ret) | ||
| 382 | return ret; | ||
| 383 | |||
| 384 | return 0; | ||
| 385 | } | ||
| 386 | #else | ||
| 387 | static int ofdrm_device_init_pci(struct ofdrm_device *odev) | ||
| 388 | { | ||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | #endif | ||
| 392 | |||
| 393 | /* | ||
| 394 | * OF display settings | ||
| 395 | */ | ||
| 396 | |||
| 397 | static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev, | ||
| 398 | struct resource *fb_res) | ||
| 399 | { | ||
| 400 | struct platform_device *pdev = to_platform_device(odev->dev.dev); | ||
| 401 | struct resource *res, *max_res = NULL; | ||
| 402 | u32 i; | ||
| 403 | |||
| 404 | for (i = 0; pdev->num_resources; ++i) { | ||
| 405 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
| 406 | if (!res) | ||
| 407 | break; /* all resources processed */ | ||
| 408 | if (resource_size(res) < resource_size(fb_res)) | ||
| 409 | continue; /* resource too small */ | ||
| 410 | if (fb_res->start && resource_contains(res, fb_res)) | ||
| 411 | return res; /* resource contains framebuffer */ | ||
| 412 | if (!max_res || resource_size(res) > resource_size(max_res)) | ||
| 413 | max_res = res; /* store largest resource as fallback */ | ||
| 414 | } | ||
| 415 | |||
| 416 | return max_res; | ||
| 417 | } | ||
| 418 | |||
| 419 | /* | ||
| 420 | * Colormap / Palette | ||
| 421 | */ | ||
| 422 | |||
| 423 | static void __iomem *get_cmap_address_of(struct ofdrm_device *odev, struct device_node *of_node, | ||
| 424 | int bar_no, unsigned long offset, unsigned long size) | ||
| 425 | { | ||
| 426 | struct drm_device *dev = &odev->dev; | ||
| 427 | const __be32 *addr_p; | ||
| 428 | u64 max_size, address; | ||
| 429 | unsigned int flags; | ||
| 430 | void __iomem *mem; | ||
| 431 | |||
| 432 | addr_p = of_get_pci_address(of_node, bar_no, &max_size, &flags); | ||
| 433 | if (!addr_p) | ||
| 434 | addr_p = of_get_address(of_node, bar_no, &max_size, &flags); | ||
| 435 | if (!addr_p) | ||
| 436 | return ERR_PTR(-ENODEV); | ||
| 437 | |||
| 438 | if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) | ||
| 439 | return ERR_PTR(-ENODEV); | ||
| 440 | |||
| 441 | if ((offset + size) >= max_size) | ||
| 442 | return ERR_PTR(-ENODEV); | ||
| 443 | |||
| 444 | address = of_translate_address(of_node, addr_p); | ||
| 445 | if (address == OF_BAD_ADDR) | ||
| 446 | return ERR_PTR(-ENODEV); | ||
| 447 | |||
| 448 | mem = devm_ioremap(dev->dev, address + offset, size); | ||
| 449 | if (!mem) | ||
| 450 | return ERR_PTR(-ENOMEM); | ||
| 451 | |||
| 452 | return mem; | ||
| 453 | } | ||
| 454 | |||
| 455 | static void __iomem *ofdrm_mach64_cmap_ioremap(struct ofdrm_device *odev, | ||
| 456 | struct device_node *of_node, | ||
| 457 | u64 fb_base) | ||
| 458 | { | ||
| 459 | struct drm_device *dev = &odev->dev; | ||
| 460 | u64 address; | ||
| 461 | void __iomem *cmap_base; | ||
| 462 | |||
| 463 | address = fb_base & 0xff000000ul; | ||
| 464 | address += 0x7ff000; | ||
| 465 | |||
| 466 | cmap_base = devm_ioremap(dev->dev, address, 0x1000); | ||
| 467 | if (!cmap_base) | ||
| 468 | return ERR_PTR(-ENOMEM); | ||
| 469 | |||
| 470 | return cmap_base; | ||
| 471 | } | ||
| 472 | |||
| 473 | static void ofdrm_mach64_cmap_write(struct ofdrm_device *odev, unsigned char index, | ||
| 474 | unsigned char r, unsigned char g, unsigned char b) | ||
| 475 | { | ||
| 476 | void __iomem *addr = odev->cmap_base + 0xcc0; | ||
| 477 | void __iomem *data = odev->cmap_base + 0xcc0 + 1; | ||
| 478 | |||
| 479 | writeb(index, addr); | ||
| 480 | writeb(r, data); | ||
| 481 | writeb(g, data); | ||
| 482 | writeb(b, data); | ||
| 483 | } | ||
| 484 | |||
| 485 | static void __iomem *ofdrm_rage128_cmap_ioremap(struct ofdrm_device *odev, | ||
| 486 | struct device_node *of_node, | ||
| 487 | u64 fb_base) | ||
| 488 | { | ||
| 489 | return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff); | ||
| 490 | } | ||
| 491 | |||
| 492 | static void ofdrm_rage128_cmap_write(struct ofdrm_device *odev, unsigned char index, | ||
| 493 | unsigned char r, unsigned char g, unsigned char b) | ||
| 494 | { | ||
| 495 | void __iomem *addr = odev->cmap_base + 0xb0; | ||
| 496 | void __iomem *data = odev->cmap_base + 0xb4; | ||
| 497 | u32 color = (r << 16) | (g << 8) | b; | ||
| 498 | |||
| 499 | writeb(index, addr); | ||
| 500 | writel(color, data); | ||
| 501 | } | ||
| 502 | |||
| 503 | static void __iomem *ofdrm_rage_m3a_cmap_ioremap(struct ofdrm_device *odev, | ||
| 504 | struct device_node *of_node, | ||
| 505 | u64 fb_base) | ||
| 506 | { | ||
| 507 | return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff); | ||
| 508 | } | ||
| 509 | |||
| 510 | static void ofdrm_rage_m3a_cmap_write(struct ofdrm_device *odev, unsigned char index, | ||
| 511 | unsigned char r, unsigned char g, unsigned char b) | ||
| 512 | { | ||
| 513 | void __iomem *dac_ctl = odev->cmap_base + 0x58; | ||
| 514 | void __iomem *addr = odev->cmap_base + 0xb0; | ||
| 515 | void __iomem *data = odev->cmap_base + 0xb4; | ||
| 516 | u32 color = (r << 16) | (g << 8) | b; | ||
| 517 | u32 val; | ||
| 518 | |||
| 519 | /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ | ||
| 520 | val = readl(dac_ctl); | ||
| 521 | val &= ~0x20; | ||
| 522 | writel(val, dac_ctl); | ||
| 523 | |||
| 524 | /* Set color at palette index */ | ||
| 525 | writeb(index, addr); | ||
| 526 | writel(color, data); | ||
| 527 | } | ||
| 528 | |||
| 529 | static void __iomem *ofdrm_rage_m3b_cmap_ioremap(struct ofdrm_device *odev, | ||
| 530 | struct device_node *of_node, | ||
| 531 | u64 fb_base) | ||
| 532 | { | ||
| 533 | return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff); | ||
| 534 | } | ||
| 535 | |||
| 536 | static void ofdrm_rage_m3b_cmap_write(struct ofdrm_device *odev, unsigned char index, | ||
| 537 | unsigned char r, unsigned char g, unsigned char b) | ||
| 538 | { | ||
| 539 | void __iomem *dac_ctl = odev->cmap_base + 0x58; | ||
| 540 | void __iomem *addr = odev->cmap_base + 0xb0; | ||
| 541 | void __iomem *data = odev->cmap_base + 0xb4; | ||
| 542 | u32 color = (r << 16) | (g << 8) | b; | ||
| 543 | u32 val; | ||
| 544 | |||
| 545 | /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ | ||
| 546 | val = readl(dac_ctl); | ||
| 547 | val |= 0x20; | ||
| 548 | writel(val, dac_ctl); | ||
| 549 | |||
| 550 | /* Set color at palette index */ | ||
| 551 | writeb(index, addr); | ||
| 552 | writel(color, data); | ||
| 553 | } | ||
| 554 | |||
| 555 | static void __iomem *ofdrm_radeon_cmap_ioremap(struct ofdrm_device *odev, | ||
| 556 | struct device_node *of_node, | ||
| 557 | u64 fb_base) | ||
| 558 | { | ||
| 559 | return get_cmap_address_of(odev, of_node, 1, 0, 0x1fff); | ||
| 560 | } | ||
| 561 | |||
| 562 | static void __iomem *ofdrm_gxt2000_cmap_ioremap(struct ofdrm_device *odev, | ||
| 563 | struct device_node *of_node, | ||
| 564 | u64 fb_base) | ||
| 565 | { | ||
| 566 | return get_cmap_address_of(odev, of_node, 0, 0x6000, 0x1000); | ||
| 567 | } | ||
| 568 | |||
| 569 | static void ofdrm_gxt2000_cmap_write(struct ofdrm_device *odev, unsigned char index, | ||
| 570 | unsigned char r, unsigned char g, unsigned char b) | ||
| 571 | { | ||
| 572 | void __iomem *data = ((unsigned int __iomem *)odev->cmap_base) + index; | ||
| 573 | u32 color = (r << 16) | (g << 8) | b; | ||
| 574 | |||
| 575 | writel(color, data); | ||
| 576 | } | ||
| 577 | |||
| 578 | static void __iomem *ofdrm_avivo_cmap_ioremap(struct ofdrm_device *odev, | ||
| 579 | struct device_node *of_node, | ||
| 580 | u64 fb_base) | ||
| 581 | { | ||
| 582 | struct device_node *of_parent; | ||
| 583 | void __iomem *cmap_base; | ||
| 584 | |||
| 585 | of_parent = of_get_parent(of_node); | ||
| 586 | cmap_base = get_cmap_address_of(odev, of_parent, 0, 0, 0x10000); | ||
| 587 | of_node_put(of_parent); | ||
| 588 | |||
| 589 | return cmap_base; | ||
| 590 | } | ||
| 591 | |||
| 592 | static void ofdrm_avivo_cmap_write(struct ofdrm_device *odev, unsigned char index, | ||
| 593 | unsigned char r, unsigned char g, unsigned char b) | ||
| 594 | { | ||
| 595 | void __iomem *lutsel = odev->cmap_base + AVIVO_DC_LUT_RW_SELECT; | ||
| 596 | void __iomem *addr = odev->cmap_base + AVIVO_DC_LUT_RW_INDEX; | ||
| 597 | void __iomem *data = odev->cmap_base + AVIVO_DC_LUT_30_COLOR; | ||
| 598 | u32 color = (r << 22) | (g << 12) | (b << 2); | ||
| 599 | |||
| 600 | /* Write to both LUTs for now */ | ||
| 601 | |||
| 602 | writel(1, lutsel); | ||
| 603 | writeb(index, addr); | ||
| 604 | writel(color, data); | ||
| 605 | |||
| 606 | writel(0, lutsel); | ||
| 607 | writeb(index, addr); | ||
| 608 | writel(color, data); | ||
| 609 | } | ||
| 610 | |||
| 611 | static void __iomem *ofdrm_qemu_cmap_ioremap(struct ofdrm_device *odev, | ||
| 612 | struct device_node *of_node, | ||
| 613 | u64 fb_base) | ||
| 614 | { | ||
| 615 | static const __be32 io_of_addr[3] = { | ||
| 616 | cpu_to_be32(0x01000000), | ||
| 617 | cpu_to_be32(0x00), | ||
| 618 | cpu_to_be32(0x00), | ||
| 619 | }; | ||
| 620 | |||
| 621 | struct drm_device *dev = &odev->dev; | ||
| 622 | u64 address; | ||
| 623 | void __iomem *cmap_base; | ||
| 624 | |||
| 625 | address = of_translate_address(of_node, io_of_addr); | ||
| 626 | if (address == OF_BAD_ADDR) | ||
| 627 | return ERR_PTR(-ENODEV); | ||
| 628 | |||
| 629 | cmap_base = devm_ioremap(dev->dev, address + 0x3c8, 2); | ||
| 630 | if (!cmap_base) | ||
| 631 | return ERR_PTR(-ENOMEM); | ||
| 632 | |||
| 633 | return cmap_base; | ||
| 634 | } | ||
| 635 | |||
| 636 | static void ofdrm_qemu_cmap_write(struct ofdrm_device *odev, unsigned char index, | ||
| 637 | unsigned char r, unsigned char g, unsigned char b) | ||
| 638 | { | ||
| 639 | void __iomem *addr = odev->cmap_base; | ||
| 640 | void __iomem *data = odev->cmap_base + 1; | ||
| 641 | |||
| 642 | writeb(index, addr); | ||
| 643 | writeb(r, data); | ||
| 644 | writeb(g, data); | ||
| 645 | writeb(b, data); | ||
| 646 | } | ||
| 647 | |||
| 648 | static void ofdrm_device_set_gamma_linear(struct ofdrm_device *odev, | ||
| 649 | const struct drm_format_info *format) | ||
| 650 | { | ||
| 651 | struct drm_device *dev = &odev->dev; | ||
| 652 | int i; | ||
| 653 | |||
| 654 | switch (format->format) { | ||
| 655 | case DRM_FORMAT_RGB565: | ||
| 656 | case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: | ||
| 657 | /* Use better interpolation, to take 32 values from 0 to 255 */ | ||
| 658 | for (i = 0; i < OFDRM_GAMMA_LUT_SIZE / 8; i++) { | ||
| 659 | unsigned char r = i * 8 + i / 4; | ||
| 660 | unsigned char g = i * 4 + i / 16; | ||
| 661 | unsigned char b = i * 8 + i / 4; | ||
| 662 | |||
| 663 | odev->funcs->cmap_write(odev, i, r, g, b); | ||
| 664 | } | ||
| 665 | /* Green has one more bit, so add padding with 0 for red and blue. */ | ||
| 666 | for (i = OFDRM_GAMMA_LUT_SIZE / 8; i < OFDRM_GAMMA_LUT_SIZE / 4; i++) { | ||
| 667 | unsigned char r = 0; | ||
| 668 | unsigned char g = i * 4 + i / 16; | ||
| 669 | unsigned char b = 0; | ||
| 670 | |||
| 671 | odev->funcs->cmap_write(odev, i, r, g, b); | ||
| 672 | } | ||
| 673 | break; | ||
| 674 | case DRM_FORMAT_XRGB8888: | ||
| 675 | case DRM_FORMAT_BGRX8888: | ||
| 676 | for (i = 0; i < OFDRM_GAMMA_LUT_SIZE; i++) | ||
| 677 | odev->funcs->cmap_write(odev, i, i, i, i); | ||
| 678 | break; | ||
| 679 | default: | ||
| 680 | drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", | ||
| 681 | &format->format); | ||
| 682 | break; | ||
| 683 | } | ||
| 684 | } | ||
| 685 | |||
| 686 | static void ofdrm_device_set_gamma(struct ofdrm_device *odev, | ||
| 687 | const struct drm_format_info *format, | ||
| 688 | struct drm_color_lut *lut) | ||
| 689 | { | ||
| 690 | struct drm_device *dev = &odev->dev; | ||
| 691 | int i; | ||
| 692 | |||
| 693 | switch (format->format) { | ||
| 694 | case DRM_FORMAT_RGB565: | ||
| 695 | case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: | ||
| 696 | /* Use better interpolation, to take 32 values from lut[0] to lut[255] */ | ||
| 697 | for (i = 0; i < OFDRM_GAMMA_LUT_SIZE / 8; i++) { | ||
| 698 | unsigned char r = lut[i * 8 + i / 4].red >> 8; | ||
| 699 | unsigned char g = lut[i * 4 + i / 16].green >> 8; | ||
| 700 | unsigned char b = lut[i * 8 + i / 4].blue >> 8; | ||
| 701 | |||
| 702 | odev->funcs->cmap_write(odev, i, r, g, b); | ||
| 703 | } | ||
| 704 | /* Green has one more bit, so add padding with 0 for red and blue. */ | ||
| 705 | for (i = OFDRM_GAMMA_LUT_SIZE / 8; i < OFDRM_GAMMA_LUT_SIZE / 4; i++) { | ||
| 706 | unsigned char r = 0; | ||
| 707 | unsigned char g = lut[i * 4 + i / 16].green >> 8; | ||
| 708 | unsigned char b = 0; | ||
| 709 | |||
| 710 | odev->funcs->cmap_write(odev, i, r, g, b); | ||
| 711 | } | ||
| 712 | break; | ||
| 713 | case DRM_FORMAT_XRGB8888: | ||
| 714 | case DRM_FORMAT_BGRX8888: | ||
| 715 | for (i = 0; i < OFDRM_GAMMA_LUT_SIZE; i++) { | ||
| 716 | unsigned char r = lut[i].red >> 8; | ||
| 717 | unsigned char g = lut[i].green >> 8; | ||
| 718 | unsigned char b = lut[i].blue >> 8; | ||
| 719 | |||
| 720 | odev->funcs->cmap_write(odev, i, r, g, b); | ||
| 721 | } | ||
| 722 | break; | ||
| 723 | default: | ||
| 724 | drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", | ||
| 725 | &format->format); | ||
| 726 | break; | ||
| 727 | } | ||
| 728 | } | ||
| 729 | |||
| 730 | /* | ||
| 731 | * Modesetting | ||
| 732 | */ | ||
| 733 | |||
| 734 | struct ofdrm_crtc_state { | ||
| 735 | struct drm_crtc_state base; | ||
| 736 | |||
| 737 | /* Primary-plane format; required for color mgmt. */ | ||
| 738 | const struct drm_format_info *format; | ||
| 739 | }; | ||
| 740 | |||
| 741 | static struct ofdrm_crtc_state *to_ofdrm_crtc_state(struct drm_crtc_state *base) | ||
| 742 | { | ||
| 743 | return container_of(base, struct ofdrm_crtc_state, base); | ||
| 744 | } | ||
| 745 | |||
| 746 | static void ofdrm_crtc_state_destroy(struct ofdrm_crtc_state *ofdrm_crtc_state) | ||
| 747 | { | ||
| 748 | __drm_atomic_helper_crtc_destroy_state(&ofdrm_crtc_state->base); | ||
| 749 | kfree(ofdrm_crtc_state); | ||
| 750 | } | ||
| 751 | |||
| 752 | /* | ||
| 753 | * Support all formats of OF display and maybe more; in order | ||
| 754 | * of preference. The display's update function will do any | ||
| 755 | * conversion necessary. | ||
| 756 | * | ||
| 757 | * TODO: Add blit helpers for remaining formats and uncomment | ||
| 758 | * constants. | ||
| 759 | */ | ||
| 760 | static const uint32_t ofdrm_primary_plane_formats[] = { | ||
| 761 | DRM_FORMAT_XRGB8888, | ||
| 762 | DRM_FORMAT_RGB565, | ||
| 763 | //DRM_FORMAT_XRGB1555, | ||
| 764 | //DRM_FORMAT_C8, | ||
| 765 | /* Big-endian formats below */ | ||
| 766 | DRM_FORMAT_BGRX8888, | ||
| 767 | DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN, | ||
| 768 | }; | ||
| 769 | |||
| 770 | static const uint64_t ofdrm_primary_plane_format_modifiers[] = { | ||
| 771 | DRM_FORMAT_MOD_LINEAR, | ||
| 772 | DRM_FORMAT_MOD_INVALID | ||
| 773 | }; | ||
| 774 | |||
| 775 | static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane, | ||
| 776 | struct drm_atomic_state *new_state) | ||
| 777 | { | ||
| 778 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); | ||
| 779 | struct drm_framebuffer *new_fb = new_plane_state->fb; | ||
| 780 | struct drm_crtc *new_crtc = new_plane_state->crtc; | ||
| 781 | struct drm_crtc_state *new_crtc_state = NULL; | ||
| 782 | struct ofdrm_crtc_state *new_ofdrm_crtc_state; | ||
| 783 | int ret; | ||
| 784 | |||
| 785 | if (new_crtc) | ||
| 786 | new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc); | ||
| 787 | |||
| 788 | ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, | ||
| 789 | DRM_PLANE_NO_SCALING, | ||
| 790 | DRM_PLANE_NO_SCALING, | ||
| 791 | false, false); | ||
| 792 | if (ret) | ||
| 793 | return ret; | ||
| 794 | else if (!new_plane_state->visible) | ||
| 795 | return 0; | ||
| 796 | |||
| 797 | new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc); | ||
| 798 | |||
| 799 | new_ofdrm_crtc_state = to_ofdrm_crtc_state(new_crtc_state); | ||
| 800 | new_ofdrm_crtc_state->format = new_fb->format; | ||
| 801 | |||
| 802 | return 0; | ||
| 803 | } | ||
| 804 | |||
| 805 | static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane, | ||
| 806 | struct drm_atomic_state *state) | ||
| 807 | { | ||
| 808 | struct drm_device *dev = plane->dev; | ||
| 809 | struct ofdrm_device *odev = ofdrm_device_of_dev(dev); | ||
| 810 | struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); | ||
| 811 | struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); | ||
| 812 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); | ||
| 813 | struct drm_framebuffer *fb = plane_state->fb; | ||
| 814 | unsigned int dst_pitch = odev->pitch; | ||
| 815 | const struct drm_format_info *dst_format = odev->format; | ||
| 816 | struct drm_atomic_helper_damage_iter iter; | ||
| 817 | struct drm_rect damage; | ||
| 818 | int ret, idx; | ||
| 819 | |||
| 820 | ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); | ||
| 821 | if (ret) | ||
| 822 | return; | ||
| 823 | |||
| 824 | if (!drm_dev_enter(dev, &idx)) | ||
| 825 | goto out_drm_gem_fb_end_cpu_access; | ||
| 826 | |||
| 827 | drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); | ||
| 828 | drm_atomic_for_each_plane_damage(&iter, &damage) { | ||
| 829 | struct iosys_map dst = odev->screen_base; | ||
| 830 | struct drm_rect dst_clip = plane_state->dst; | ||
| 831 | |||
| 832 | if (!drm_rect_intersect(&dst_clip, &damage)) | ||
| 833 | continue; | ||
| 834 | |||
| 835 | iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip)); | ||
| 836 | drm_fb_blit(&dst, &dst_pitch, dst_format->format, shadow_plane_state->data, fb, | ||
| 837 | &damage); | ||
| 838 | } | ||
| 839 | |||
| 840 | drm_dev_exit(idx); | ||
| 841 | out_drm_gem_fb_end_cpu_access: | ||
| 842 | drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); | ||
| 843 | } | ||
| 844 | |||
| 845 | static void ofdrm_primary_plane_helper_atomic_disable(struct drm_plane *plane, | ||
| 846 | struct drm_atomic_state *state) | ||
| 847 | { | ||
| 848 | struct drm_device *dev = plane->dev; | ||
| 849 | struct ofdrm_device *odev = ofdrm_device_of_dev(dev); | ||
| 850 | struct iosys_map dst = odev->screen_base; | ||
| 851 | struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); | ||
| 852 | void __iomem *dst_vmap = dst.vaddr_iomem; /* TODO: Use mapping abstraction */ | ||
| 853 | unsigned int dst_pitch = odev->pitch; | ||
| 854 | const struct drm_format_info *dst_format = odev->format; | ||
| 855 | struct drm_rect dst_clip; | ||
| 856 | unsigned long lines, linepixels, i; | ||
| 857 | int idx; | ||
| 858 | |||
| 859 | drm_rect_init(&dst_clip, | ||
| 860 | plane_state->src_x >> 16, plane_state->src_y >> 16, | ||
| 861 | plane_state->src_w >> 16, plane_state->src_h >> 16); | ||
| 862 | |||
| 863 | lines = drm_rect_height(&dst_clip); | ||
| 864 | linepixels = drm_rect_width(&dst_clip); | ||
| 865 | |||
| 866 | if (!drm_dev_enter(dev, &idx)) | ||
| 867 | return; | ||
| 868 | |||
| 869 | /* Clear buffer to black if disabled */ | ||
| 870 | dst_vmap += drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip); | ||
| 871 | for (i = 0; i < lines; ++i) { | ||
| 872 | memset_io(dst_vmap, 0, linepixels * dst_format->cpp[0]); | ||
| 873 | dst_vmap += dst_pitch; | ||
| 874 | } | ||
| 875 | |||
| 876 | drm_dev_exit(idx); | ||
| 877 | } | ||
| 878 | |||
| 879 | static const struct drm_plane_helper_funcs ofdrm_primary_plane_helper_funcs = { | ||
| 880 | DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, | ||
| 881 | .atomic_check = ofdrm_primary_plane_helper_atomic_check, | ||
| 882 | .atomic_update = ofdrm_primary_plane_helper_atomic_update, | ||
| 883 | .atomic_disable = ofdrm_primary_plane_helper_atomic_disable, | ||
| 884 | }; | ||
| 885 | |||
| 886 | static const struct drm_plane_funcs ofdrm_primary_plane_funcs = { | ||
| 887 | .update_plane = drm_atomic_helper_update_plane, | ||
| 888 | .disable_plane = drm_atomic_helper_disable_plane, | ||
| 889 | .destroy = drm_plane_cleanup, | ||
| 890 | DRM_GEM_SHADOW_PLANE_FUNCS, | ||
| 891 | }; | ||
| 892 | |||
| 893 | static enum drm_mode_status ofdrm_crtc_helper_mode_valid(struct drm_crtc *crtc, | ||
| 894 | const struct drm_display_mode *mode) | ||
| 895 | { | ||
| 896 | struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev); | ||
| 897 | |||
| 898 | return drm_crtc_helper_mode_valid_fixed(crtc, mode, &odev->mode); | ||
| 899 | } | ||
| 900 | |||
| 901 | static int ofdrm_crtc_helper_atomic_check(struct drm_crtc *crtc, | ||
| 902 | struct drm_atomic_state *new_state) | ||
| 903 | { | ||
| 904 | static const size_t gamma_lut_length = OFDRM_GAMMA_LUT_SIZE * sizeof(struct drm_color_lut); | ||
| 905 | |||
| 906 | struct drm_device *dev = crtc->dev; | ||
| 907 | struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); | ||
| 908 | int ret; | ||
| 909 | |||
| 910 | if (!new_crtc_state->enable) | ||
| 911 | return 0; | ||
| 912 | |||
| 913 | ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); | ||
| 914 | if (ret) | ||
| 915 | return ret; | ||
| 916 | |||
| 917 | if (new_crtc_state->color_mgmt_changed) { | ||
| 918 | struct drm_property_blob *gamma_lut = new_crtc_state->gamma_lut; | ||
| 919 | |||
| 920 | if (gamma_lut && (gamma_lut->length != gamma_lut_length)) { | ||
| 921 | drm_dbg(dev, "Incorrect gamma_lut length %zu\n", gamma_lut->length); | ||
| 922 | return -EINVAL; | ||
| 923 | } | ||
| 924 | } | ||
| 925 | |||
| 926 | return 0; | ||
| 927 | } | ||
| 928 | |||
| 929 | static void ofdrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) | ||
| 930 | { | ||
| 931 | struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev); | ||
| 932 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); | ||
| 933 | struct ofdrm_crtc_state *ofdrm_crtc_state = to_ofdrm_crtc_state(crtc_state); | ||
| 934 | |||
| 935 | if (crtc_state->enable && crtc_state->color_mgmt_changed) { | ||
| 936 | const struct drm_format_info *format = ofdrm_crtc_state->format; | ||
| 937 | |||
| 938 | if (crtc_state->gamma_lut) | ||
| 939 | ofdrm_device_set_gamma(odev, format, crtc_state->gamma_lut->data); | ||
| 940 | else | ||
| 941 | ofdrm_device_set_gamma_linear(odev, format); | ||
| 942 | } | ||
| 943 | } | ||
| 944 | |||
| 945 | /* | ||
| 946 | * The CRTC is always enabled. Screen updates are performed by | ||
| 947 | * the primary plane's atomic_update function. Disabling clears | ||
| 948 | * the screen in the primary plane's atomic_disable function. | ||
| 949 | */ | ||
| 950 | static const struct drm_crtc_helper_funcs ofdrm_crtc_helper_funcs = { | ||
| 951 | .mode_valid = ofdrm_crtc_helper_mode_valid, | ||
| 952 | .atomic_check = ofdrm_crtc_helper_atomic_check, | ||
| 953 | .atomic_flush = ofdrm_crtc_helper_atomic_flush, | ||
| 954 | }; | ||
| 955 | |||
| 956 | static void ofdrm_crtc_reset(struct drm_crtc *crtc) | ||
| 957 | { | ||
| 958 | struct ofdrm_crtc_state *ofdrm_crtc_state = | ||
| 959 | kzalloc(sizeof(*ofdrm_crtc_state), GFP_KERNEL); | ||
| 960 | |||
| 961 | if (crtc->state) | ||
| 962 | ofdrm_crtc_state_destroy(to_ofdrm_crtc_state(crtc->state)); | ||
| 963 | |||
| 964 | if (ofdrm_crtc_state) | ||
| 965 | __drm_atomic_helper_crtc_reset(crtc, &ofdrm_crtc_state->base); | ||
| 966 | else | ||
| 967 | __drm_atomic_helper_crtc_reset(crtc, NULL); | ||
| 968 | } | ||
| 969 | |||
| 970 | static struct drm_crtc_state *ofdrm_crtc_atomic_duplicate_state(struct drm_crtc *crtc) | ||
| 971 | { | ||
| 972 | struct drm_device *dev = crtc->dev; | ||
| 973 | struct drm_crtc_state *crtc_state = crtc->state; | ||
| 974 | struct ofdrm_crtc_state *new_ofdrm_crtc_state; | ||
| 975 | struct ofdrm_crtc_state *ofdrm_crtc_state; | ||
| 976 | |||
| 977 | if (drm_WARN_ON(dev, !crtc_state)) | ||
| 978 | return NULL; | ||
| 979 | |||
| 980 | new_ofdrm_crtc_state = kzalloc(sizeof(*new_ofdrm_crtc_state), GFP_KERNEL); | ||
| 981 | if (!new_ofdrm_crtc_state) | ||
| 982 | return NULL; | ||
| 983 | |||
| 984 | ofdrm_crtc_state = to_ofdrm_crtc_state(crtc_state); | ||
| 985 | |||
| 986 | __drm_atomic_helper_crtc_duplicate_state(crtc, &new_ofdrm_crtc_state->base); | ||
| 987 | new_ofdrm_crtc_state->format = ofdrm_crtc_state->format; | ||
| 988 | |||
| 989 | return &new_ofdrm_crtc_state->base; | ||
| 990 | } | ||
| 991 | |||
| 992 | static void ofdrm_crtc_atomic_destroy_state(struct drm_crtc *crtc, | ||
| 993 | struct drm_crtc_state *crtc_state) | ||
| 994 | { | ||
| 995 | ofdrm_crtc_state_destroy(to_ofdrm_crtc_state(crtc_state)); | ||
| 996 | } | ||
| 997 | |||
| 998 | static const struct drm_crtc_funcs ofdrm_crtc_funcs = { | ||
| 999 | .reset = ofdrm_crtc_reset, | ||
| 1000 | .destroy = drm_crtc_cleanup, | ||
| 1001 | .set_config = drm_atomic_helper_set_config, | ||
| 1002 | .page_flip = drm_atomic_helper_page_flip, | ||
| 1003 | .atomic_duplicate_state = ofdrm_crtc_atomic_duplicate_state, | ||
| 1004 | .atomic_destroy_state = ofdrm_crtc_atomic_destroy_state, | ||
| 1005 | }; | ||
| 1006 | |||
| 1007 | static int ofdrm_connector_helper_get_modes(struct drm_connector *connector) | ||
| 1008 | { | ||
| 1009 | struct ofdrm_device *odev = ofdrm_device_of_dev(connector->dev); | ||
| 1010 | |||
| 1011 | return drm_connector_helper_get_modes_fixed(connector, &odev->mode); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | static const struct drm_connector_helper_funcs ofdrm_connector_helper_funcs = { | ||
| 1015 | .get_modes = ofdrm_connector_helper_get_modes, | ||
| 1016 | }; | ||
| 1017 | |||
| 1018 | static const struct drm_connector_funcs ofdrm_connector_funcs = { | ||
| 1019 | .reset = drm_atomic_helper_connector_reset, | ||
| 1020 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 1021 | .destroy = drm_connector_cleanup, | ||
| 1022 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
| 1023 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
| 1024 | }; | ||
| 1025 | |||
| 1026 | static const struct drm_mode_config_funcs ofdrm_mode_config_funcs = { | ||
| 1027 | .fb_create = drm_gem_fb_create_with_dirty, | ||
| 1028 | .atomic_check = drm_atomic_helper_check, | ||
| 1029 | .atomic_commit = drm_atomic_helper_commit, | ||
| 1030 | }; | ||
| 1031 | |||
| 1032 | /* | ||
| 1033 | * Init / Cleanup | ||
| 1034 | */ | ||
| 1035 | |||
| 1036 | static const struct ofdrm_device_funcs ofdrm_unknown_device_funcs = { | ||
| 1037 | }; | ||
| 1038 | |||
| 1039 | static const struct ofdrm_device_funcs ofdrm_mach64_device_funcs = { | ||
| 1040 | .cmap_ioremap = ofdrm_mach64_cmap_ioremap, | ||
| 1041 | .cmap_write = ofdrm_mach64_cmap_write, | ||
| 1042 | }; | ||
| 1043 | |||
| 1044 | static const struct ofdrm_device_funcs ofdrm_rage128_device_funcs = { | ||
| 1045 | .cmap_ioremap = ofdrm_rage128_cmap_ioremap, | ||
| 1046 | .cmap_write = ofdrm_rage128_cmap_write, | ||
| 1047 | }; | ||
| 1048 | |||
| 1049 | static const struct ofdrm_device_funcs ofdrm_rage_m3a_device_funcs = { | ||
| 1050 | .cmap_ioremap = ofdrm_rage_m3a_cmap_ioremap, | ||
| 1051 | .cmap_write = ofdrm_rage_m3a_cmap_write, | ||
| 1052 | }; | ||
| 1053 | |||
| 1054 | static const struct ofdrm_device_funcs ofdrm_rage_m3b_device_funcs = { | ||
| 1055 | .cmap_ioremap = ofdrm_rage_m3b_cmap_ioremap, | ||
| 1056 | .cmap_write = ofdrm_rage_m3b_cmap_write, | ||
| 1057 | }; | ||
| 1058 | |||
| 1059 | static const struct ofdrm_device_funcs ofdrm_radeon_device_funcs = { | ||
| 1060 | .cmap_ioremap = ofdrm_radeon_cmap_ioremap, | ||
| 1061 | .cmap_write = ofdrm_rage128_cmap_write, /* same as Rage128 */ | ||
| 1062 | }; | ||
| 1063 | |||
| 1064 | static const struct ofdrm_device_funcs ofdrm_gxt2000_device_funcs = { | ||
| 1065 | .cmap_ioremap = ofdrm_gxt2000_cmap_ioremap, | ||
| 1066 | .cmap_write = ofdrm_gxt2000_cmap_write, | ||
| 1067 | }; | ||
| 1068 | |||
| 1069 | static const struct ofdrm_device_funcs ofdrm_avivo_device_funcs = { | ||
| 1070 | .cmap_ioremap = ofdrm_avivo_cmap_ioremap, | ||
| 1071 | .cmap_write = ofdrm_avivo_cmap_write, | ||
| 1072 | }; | ||
| 1073 | |||
| 1074 | static const struct ofdrm_device_funcs ofdrm_qemu_device_funcs = { | ||
| 1075 | .cmap_ioremap = ofdrm_qemu_cmap_ioremap, | ||
| 1076 | .cmap_write = ofdrm_qemu_cmap_write, | ||
| 1077 | }; | ||
| 1078 | |||
| 1079 | static struct drm_display_mode ofdrm_mode(unsigned int width, unsigned int height) | ||
| 1080 | { | ||
| 1081 | /* | ||
| 1082 | * Assume a monitor resolution of 96 dpi to | ||
| 1083 | * get a somewhat reasonable screen size. | ||
| 1084 | */ | ||
| 1085 | const struct drm_display_mode mode = { | ||
| 1086 | DRM_MODE_INIT(60, width, height, | ||
| 1087 | DRM_MODE_RES_MM(width, 96ul), | ||
| 1088 | DRM_MODE_RES_MM(height, 96ul)) | ||
| 1089 | }; | ||
| 1090 | |||
| 1091 | return mode; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, | ||
| 1095 | struct platform_device *pdev) | ||
| 1096 | { | ||
| 1097 | struct device_node *of_node = pdev->dev.of_node; | ||
| 1098 | struct ofdrm_device *odev; | ||
| 1099 | struct drm_device *dev; | ||
| 1100 | enum ofdrm_model model; | ||
| 1101 | bool big_endian; | ||
| 1102 | int width, height, depth, linebytes; | ||
| 1103 | const struct drm_format_info *format; | ||
| 1104 | u64 address; | ||
| 1105 | resource_size_t fb_size, fb_base, fb_pgbase, fb_pgsize; | ||
| 1106 | struct resource *res, *mem; | ||
| 1107 | void __iomem *screen_base; | ||
| 1108 | struct drm_plane *primary_plane; | ||
| 1109 | struct drm_crtc *crtc; | ||
| 1110 | struct drm_encoder *encoder; | ||
| 1111 | struct drm_connector *connector; | ||
| 1112 | unsigned long max_width, max_height; | ||
| 1113 | size_t nformats; | ||
| 1114 | int ret; | ||
| 1115 | |||
| 1116 | odev = devm_drm_dev_alloc(&pdev->dev, drv, struct ofdrm_device, dev); | ||
| 1117 | if (IS_ERR(odev)) | ||
| 1118 | return ERR_CAST(odev); | ||
| 1119 | dev = &odev->dev; | ||
| 1120 | platform_set_drvdata(pdev, dev); | ||
| 1121 | |||
| 1122 | ret = ofdrm_device_init_pci(odev); | ||
| 1123 | if (ret) | ||
| 1124 | return ERR_PTR(ret); | ||
| 1125 | |||
| 1126 | /* | ||
| 1127 | * OF display-node settings | ||
| 1128 | */ | ||
| 1129 | |||
| 1130 | model = display_get_model_of(dev, of_node); | ||
| 1131 | drm_dbg(dev, "detected model %d\n", model); | ||
| 1132 | |||
| 1133 | switch (model) { | ||
| 1134 | case OFDRM_MODEL_UNKNOWN: | ||
| 1135 | odev->funcs = &ofdrm_unknown_device_funcs; | ||
| 1136 | break; | ||
| 1137 | case OFDRM_MODEL_MACH64: | ||
| 1138 | odev->funcs = &ofdrm_mach64_device_funcs; | ||
| 1139 | break; | ||
| 1140 | case OFDRM_MODEL_RAGE128: | ||
| 1141 | odev->funcs = &ofdrm_rage128_device_funcs; | ||
| 1142 | break; | ||
| 1143 | case OFDRM_MODEL_RAGE_M3A: | ||
| 1144 | odev->funcs = &ofdrm_rage_m3a_device_funcs; | ||
| 1145 | break; | ||
| 1146 | case OFDRM_MODEL_RAGE_M3B: | ||
| 1147 | odev->funcs = &ofdrm_rage_m3b_device_funcs; | ||
| 1148 | break; | ||
| 1149 | case OFDRM_MODEL_RADEON: | ||
| 1150 | odev->funcs = &ofdrm_radeon_device_funcs; | ||
| 1151 | break; | ||
| 1152 | case OFDRM_MODEL_GXT2000: | ||
| 1153 | odev->funcs = &ofdrm_gxt2000_device_funcs; | ||
| 1154 | break; | ||
| 1155 | case OFDRM_MODEL_AVIVO: | ||
| 1156 | odev->funcs = &ofdrm_avivo_device_funcs; | ||
| 1157 | break; | ||
| 1158 | case OFDRM_MODEL_QEMU: | ||
| 1159 | odev->funcs = &ofdrm_qemu_device_funcs; | ||
| 1160 | break; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | big_endian = display_get_big_endian_of(dev, of_node); | ||
| 1164 | |||
| 1165 | width = display_get_width_of(dev, of_node); | ||
| 1166 | if (width < 0) | ||
| 1167 | return ERR_PTR(width); | ||
| 1168 | height = display_get_height_of(dev, of_node); | ||
| 1169 | if (height < 0) | ||
| 1170 | return ERR_PTR(height); | ||
| 1171 | depth = display_get_depth_of(dev, of_node); | ||
| 1172 | if (depth < 0) | ||
| 1173 | return ERR_PTR(depth); | ||
| 1174 | linebytes = display_get_linebytes_of(dev, of_node); | ||
| 1175 | if (linebytes < 0) | ||
| 1176 | return ERR_PTR(linebytes); | ||
| 1177 | |||
| 1178 | format = display_get_validated_format(dev, depth, big_endian); | ||
| 1179 | if (IS_ERR(format)) | ||
| 1180 | return ERR_CAST(format); | ||
| 1181 | if (!linebytes) { | ||
| 1182 | linebytes = drm_format_info_min_pitch(format, 0, width); | ||
| 1183 | if (drm_WARN_ON(dev, !linebytes)) | ||
| 1184 | return ERR_PTR(-EINVAL); | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | fb_size = linebytes * height; | ||
| 1188 | |||
| 1189 | /* | ||
| 1190 | * Try to figure out the address of the framebuffer. Unfortunately, Open | ||
| 1191 | * Firmware doesn't provide a standard way to do so. All we can do is a | ||
| 1192 | * dodgy heuristic that happens to work in practice. | ||
| 1193 | * | ||
| 1194 | * On most machines, the "address" property contains what we need, though | ||
| 1195 | * not on Matrox cards found in IBM machines. What appears to give good | ||
| 1196 | * results is to go through the PCI ranges and pick one that encloses the | ||
| 1197 | * "address" property. If none match, we pick the largest. | ||
| 1198 | */ | ||
| 1199 | address = display_get_address_of(dev, of_node); | ||
| 1200 | if (address != OF_BAD_ADDR) { | ||
| 1201 | struct resource fb_res = DEFINE_RES_MEM(address, fb_size); | ||
| 1202 | |||
| 1203 | res = ofdrm_find_fb_resource(odev, &fb_res); | ||
| 1204 | if (!res) | ||
| 1205 | return ERR_PTR(-EINVAL); | ||
| 1206 | if (resource_contains(res, &fb_res)) | ||
| 1207 | fb_base = address; | ||
| 1208 | else | ||
| 1209 | fb_base = res->start; | ||
| 1210 | } else { | ||
| 1211 | struct resource fb_res = DEFINE_RES_MEM(0u, fb_size); | ||
| 1212 | |||
| 1213 | res = ofdrm_find_fb_resource(odev, &fb_res); | ||
| 1214 | if (!res) | ||
| 1215 | return ERR_PTR(-EINVAL); | ||
| 1216 | fb_base = res->start; | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | /* | ||
| 1220 | * I/O resources | ||
| 1221 | */ | ||
| 1222 | |||
| 1223 | fb_pgbase = round_down(fb_base, PAGE_SIZE); | ||
| 1224 | fb_pgsize = fb_base - fb_pgbase + round_up(fb_size, PAGE_SIZE); | ||
| 1225 | |||
| 1226 | ret = devm_aperture_acquire_from_firmware(dev, fb_pgbase, fb_pgsize); | ||
| 1227 | if (ret) { | ||
| 1228 | drm_err(dev, "could not acquire memory range %pr: error %d\n", &res, ret); | ||
| 1229 | return ERR_PTR(ret); | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | mem = devm_request_mem_region(&pdev->dev, fb_pgbase, fb_pgsize, drv->name); | ||
| 1233 | if (!mem) { | ||
| 1234 | drm_warn(dev, "could not acquire memory region %pr\n", &res); | ||
| 1235 | return ERR_PTR(-ENOMEM); | ||
| 1236 | } | ||
| 1237 | |||
| 1238 | screen_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); | ||
| 1239 | if (!screen_base) | ||
| 1240 | return ERR_PTR(-ENOMEM); | ||
| 1241 | |||
| 1242 | if (odev->funcs->cmap_ioremap) { | ||
| 1243 | void __iomem *cmap_base = odev->funcs->cmap_ioremap(odev, of_node, fb_base); | ||
| 1244 | |||
| 1245 | if (IS_ERR(cmap_base)) { | ||
| 1246 | /* Don't fail; continue without colormap */ | ||
| 1247 | drm_warn(dev, "could not find colormap: error %ld\n", PTR_ERR(cmap_base)); | ||
| 1248 | } else { | ||
| 1249 | odev->cmap_base = cmap_base; | ||
| 1250 | } | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | /* | ||
| 1254 | * Firmware framebuffer | ||
| 1255 | */ | ||
| 1256 | |||
| 1257 | iosys_map_set_vaddr_iomem(&odev->screen_base, screen_base); | ||
| 1258 | odev->mode = ofdrm_mode(width, height); | ||
| 1259 | odev->format = format; | ||
| 1260 | odev->pitch = linebytes; | ||
| 1261 | |||
| 1262 | drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&odev->mode)); | ||
| 1263 | drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n", | ||
| 1264 | &format->format, width, height, linebytes); | ||
| 1265 | |||
| 1266 | /* | ||
| 1267 | * Mode-setting pipeline | ||
| 1268 | */ | ||
| 1269 | |||
| 1270 | ret = drmm_mode_config_init(dev); | ||
| 1271 | if (ret) | ||
| 1272 | return ERR_PTR(ret); | ||
| 1273 | |||
| 1274 | max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH); | ||
| 1275 | max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT); | ||
| 1276 | |||
| 1277 | dev->mode_config.min_width = width; | ||
| 1278 | dev->mode_config.max_width = max_width; | ||
| 1279 | dev->mode_config.min_height = height; | ||
| 1280 | dev->mode_config.max_height = max_height; | ||
| 1281 | dev->mode_config.funcs = &ofdrm_mode_config_funcs; | ||
| 1282 | switch (depth) { | ||
| 1283 | case 32: | ||
| 1284 | dev->mode_config.preferred_depth = 24; | ||
| 1285 | break; | ||
| 1286 | default: | ||
| 1287 | dev->mode_config.preferred_depth = depth; | ||
| 1288 | break; | ||
| 1289 | } | ||
| 1290 | dev->mode_config.quirk_addfb_prefer_host_byte_order = true; | ||
| 1291 | |||
| 1292 | /* Primary plane */ | ||
| 1293 | |||
| 1294 | nformats = drm_fb_build_fourcc_list(dev, &format->format, 1, | ||
| 1295 | ofdrm_primary_plane_formats, | ||
| 1296 | ARRAY_SIZE(ofdrm_primary_plane_formats), | ||
| 1297 | odev->formats, ARRAY_SIZE(odev->formats)); | ||
| 1298 | |||
| 1299 | primary_plane = &odev->primary_plane; | ||
| 1300 | ret = drm_universal_plane_init(dev, primary_plane, 0, &ofdrm_primary_plane_funcs, | ||
| 1301 | odev->formats, nformats, | ||
| 1302 | ofdrm_primary_plane_format_modifiers, | ||
| 1303 | DRM_PLANE_TYPE_PRIMARY, NULL); | ||
| 1304 | if (ret) | ||
| 1305 | return ERR_PTR(ret); | ||
| 1306 | drm_plane_helper_add(primary_plane, &ofdrm_primary_plane_helper_funcs); | ||
| 1307 | drm_plane_enable_fb_damage_clips(primary_plane); | ||
| 1308 | |||
| 1309 | /* CRTC */ | ||
| 1310 | |||
| 1311 | crtc = &odev->crtc; | ||
| 1312 | ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, | ||
| 1313 | &ofdrm_crtc_funcs, NULL); | ||
| 1314 | if (ret) | ||
| 1315 | return ERR_PTR(ret); | ||
| 1316 | drm_crtc_helper_add(crtc, &ofdrm_crtc_helper_funcs); | ||
| 1317 | |||
| 1318 | if (odev->cmap_base) { | ||
| 1319 | drm_mode_crtc_set_gamma_size(crtc, OFDRM_GAMMA_LUT_SIZE); | ||
| 1320 | drm_crtc_enable_color_mgmt(crtc, 0, false, OFDRM_GAMMA_LUT_SIZE); | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | /* Encoder */ | ||
| 1324 | |||
| 1325 | encoder = &odev->encoder; | ||
| 1326 | ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE); | ||
| 1327 | if (ret) | ||
| 1328 | return ERR_PTR(ret); | ||
| 1329 | encoder->possible_crtcs = drm_crtc_mask(crtc); | ||
| 1330 | |||
| 1331 | /* Connector */ | ||
| 1332 | |||
| 1333 | connector = &odev->connector; | ||
| 1334 | ret = drm_connector_init(dev, connector, &ofdrm_connector_funcs, | ||
| 1335 | DRM_MODE_CONNECTOR_Unknown); | ||
| 1336 | if (ret) | ||
| 1337 | return ERR_PTR(ret); | ||
| 1338 | drm_connector_helper_add(connector, &ofdrm_connector_helper_funcs); | ||
| 1339 | drm_connector_set_panel_orientation_with_quirk(connector, | ||
| 1340 | DRM_MODE_PANEL_ORIENTATION_UNKNOWN, | ||
| 1341 | width, height); | ||
| 1342 | |||
| 1343 | ret = drm_connector_attach_encoder(connector, encoder); | ||
| 1344 | if (ret) | ||
| 1345 | return ERR_PTR(ret); | ||
| 1346 | |||
| 1347 | drm_mode_config_reset(dev); | ||
| 1348 | |||
| 1349 | return odev; | ||
| 1350 | } | ||
| 1351 | |||
| 1352 | /* | ||
| 1353 | * DRM driver | ||
| 1354 | */ | ||
| 1355 | |||
| 1356 | DEFINE_DRM_GEM_FOPS(ofdrm_fops); | ||
| 1357 | |||
| 1358 | static struct drm_driver ofdrm_driver = { | ||
| 1359 | DRM_GEM_SHMEM_DRIVER_OPS, | ||
| 1360 | .name = DRIVER_NAME, | ||
| 1361 | .desc = DRIVER_DESC, | ||
| 1362 | .date = DRIVER_DATE, | ||
| 1363 | .major = DRIVER_MAJOR, | ||
| 1364 | .minor = DRIVER_MINOR, | ||
| 1365 | .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, | ||
| 1366 | .fops = &ofdrm_fops, | ||
| 1367 | }; | ||
| 1368 | |||
| 1369 | /* | ||
| 1370 | * Platform driver | ||
| 1371 | */ | ||
| 1372 | |||
| 1373 | static int ofdrm_probe(struct platform_device *pdev) | ||
| 1374 | { | ||
| 1375 | struct ofdrm_device *odev; | ||
| 1376 | struct drm_device *dev; | ||
| 1377 | int ret; | ||
| 1378 | |||
| 1379 | odev = ofdrm_device_create(&ofdrm_driver, pdev); | ||
| 1380 | if (IS_ERR(odev)) | ||
| 1381 | return PTR_ERR(odev); | ||
| 1382 | dev = &odev->dev; | ||
| 1383 | |||
| 1384 | ret = drm_dev_register(dev, 0); | ||
| 1385 | if (ret) | ||
| 1386 | return ret; | ||
| 1387 | |||
| 1388 | /* | ||
| 1389 | * FIXME: 24-bit color depth does not work reliably with a 32-bpp | ||
| 1390 | * value. Force the bpp value of the scanout buffer's format. | ||
| 1391 | */ | ||
| 1392 | drm_fbdev_generic_setup(dev, drm_format_info_bpp(odev->format, 0)); | ||
| 1393 | |||
| 1394 | return 0; | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | static int ofdrm_remove(struct platform_device *pdev) | ||
| 1398 | { | ||
| 1399 | struct drm_device *dev = platform_get_drvdata(pdev); | ||
| 1400 | |||
| 1401 | drm_dev_unplug(dev); | ||
| 1402 | |||
| 1403 | return 0; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | static const struct of_device_id ofdrm_of_match_display[] = { | ||
| 1407 | { .compatible = "display", }, | ||
| 1408 | { }, | ||
| 1409 | }; | ||
| 1410 | MODULE_DEVICE_TABLE(of, ofdrm_of_match_display); | ||
| 1411 | |||
| 1412 | static struct platform_driver ofdrm_platform_driver = { | ||
| 1413 | .driver = { | ||
| 1414 | .name = "of-display", | ||
| 1415 | .of_match_table = ofdrm_of_match_display, | ||
| 1416 | }, | ||
| 1417 | .probe = ofdrm_probe, | ||
| 1418 | .remove = ofdrm_remove, | ||
| 1419 | }; | ||
| 1420 | |||
| 1421 | module_platform_driver(ofdrm_platform_driver); | ||
| 1422 | |||
| 1423 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 1424 | MODULE_LICENSE("GPL"); | ||
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | #include <drm/drm_atomic.h> | 11 | #include <drm/drm_atomic.h> |
| 12 | #include <drm/drm_atomic_state_helper.h> | 12 | #include <drm/drm_atomic_state_helper.h> |
| 13 | #include <drm/drm_connector.h> | 13 | #include <drm/drm_connector.h> |
| 14 | #include <drm/drm_crtc_helper.h> | ||
| 14 | #include <drm/drm_damage_helper.h> | 15 | #include <drm/drm_damage_helper.h> |
| 15 | #include <drm/drm_device.h> | 16 | #include <drm/drm_device.h> |
| 16 | #include <drm/drm_drv.h> | 17 | #include <drm/drm_drv.h> |
| @@ -545,19 +546,6 @@ static enum drm_mode_status simpledrm_crtc_helper_mode_valid(struct drm_crtc *cr · 528 unmodified lines | |||
| 545 | return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sdev->mode); | 546 | return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sdev->mode); |
| 546 | } | 547 | } |
| 547 | 548 | ||
| 548 | static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc, | ||
| 549 | struct drm_atomic_state *new_state) | ||
| 550 | { | ||
| 551 | struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); | ||
| 552 | int ret; | ||
| 553 | |||
| 554 | ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); | ||
| 555 | if (ret) | ||
| 556 | return ret; | ||
| 557 | |||
| 558 | return drm_atomic_add_affected_planes(new_state, crtc); | ||
| 559 | } | ||
| 560 | |||
| 561 | /* | 549 | /* |
| 562 | * The CRTC is always enabled. Screen updates are performed by | 550 | * The CRTC is always enabled. Screen updates are performed by |
| 563 | * the primary plane's atomic_update function. Disabling clears | 551 | * the primary plane's atomic_update function. Disabling clears |
| @@ -565,7 +553,7 @@ static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc, · 1 unmodified line | |||
| 565 | */ | 553 | */ |
| 566 | static const struct drm_crtc_helper_funcs simpledrm_crtc_helper_funcs = { | 554 | static const struct drm_crtc_helper_funcs simpledrm_crtc_helper_funcs = { |
| 567 | .mode_valid = simpledrm_crtc_helper_mode_valid, | 555 | .mode_valid = simpledrm_crtc_helper_mode_valid, |
| 568 | .atomic_check = simpledrm_crtc_helper_atomic_check, | 556 | .atomic_check = drm_crtc_helper_atomic_check, |
| 569 | }; | 557 | }; |
| 570 | 558 | ||
| 571 | static const struct drm_crtc_funcs simpledrm_crtc_funcs = { | 559 | static const struct drm_crtc_funcs simpledrm_crtc_funcs = { |
| @@ -229,7 +229,6 @@ int ttm_range_man_fini_nocheck(struct ttm_device *bdev, · 228 unmodified lines | |||
| 229 | return ret; | 229 | return ret; |
| 230 | 230 | ||
| 231 | spin_lock(&rman->lock); | 231 | spin_lock(&rman->lock); |
| 232 | drm_mm_clean(mm); | ||
| 233 | drm_mm_takedown(mm); | 232 | drm_mm_takedown(mm); |
| 234 | spin_unlock(&rman->lock); | 233 | spin_unlock(&rman->lock); |
| 235 | 234 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_main.o udl_transfer.o | 2 | udl-y := udl_drv.o udl_modeset.o udl_main.o udl_transfer.o |
| 3 | 3 | ||
| 4 | obj-$(CONFIG_DRM_UDL) := udl.o | 4 | obj-$(CONFIG_DRM_UDL) := udl.o |
| @@ -1,139 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2012 Red Hat | ||
| 4 | * based in parts on udlfb.c: | ||
| 5 | * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it> | ||
| 6 | * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com> | ||
| 7 | * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <drm/drm_atomic_state_helper.h> | ||
| 11 | #include <drm/drm_edid.h> | ||
| 12 | #include <drm/drm_crtc_helper.h> | ||
| 13 | #include <drm/drm_probe_helper.h> | ||
| 14 | |||
| 15 | #include "udl_connector.h" | ||
| 16 | #include "udl_drv.h" | ||
| 17 | |||
| 18 | static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, | ||
| 19 | size_t len) | ||
| 20 | { | ||
| 21 | int ret, i; | ||
| 22 | u8 *read_buff; | ||
| 23 | struct udl_device *udl = data; | ||
| 24 | struct usb_device *udev = udl_to_usb_device(udl); | ||
| 25 | |||
| 26 | read_buff = kmalloc(2, GFP_KERNEL); | ||
| 27 | if (!read_buff) | ||
| 28 | return -1; | ||
| 29 | |||
| 30 | for (i = 0; i < len; i++) { | ||
| 31 | int bval = (i + block * EDID_LENGTH) << 8; | ||
| 32 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | ||
| 33 | 0x02, (0x80 | (0x02 << 5)), bval, | ||
| 34 | 0xA1, read_buff, 2, 1000); | ||
| 35 | if (ret < 1) { | ||
| 36 | DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); | ||
| 37 | kfree(read_buff); | ||
| 38 | return -1; | ||
| 39 | } | ||
| 40 | buf[i] = read_buff[1]; | ||
| 41 | } | ||
| 42 | |||
| 43 | kfree(read_buff); | ||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | |||
| 47 | static int udl_get_modes(struct drm_connector *connector) | ||
| 48 | { | ||
| 49 | struct udl_drm_connector *udl_connector = | ||
| 50 | container_of(connector, | ||
| 51 | struct udl_drm_connector, | ||
| 52 | connector); | ||
| 53 | |||
| 54 | drm_connector_update_edid_property(connector, udl_connector->edid); | ||
| 55 | if (udl_connector->edid) | ||
| 56 | return drm_add_edid_modes(connector, udl_connector->edid); | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | static enum drm_mode_status udl_mode_valid(struct drm_connector *connector, | ||
| 61 | struct drm_display_mode *mode) | ||
| 62 | { | ||
| 63 | struct udl_device *udl = to_udl(connector->dev); | ||
| 64 | if (!udl->sku_pixel_limit) | ||
| 65 | return 0; | ||
| 66 | |||
| 67 | if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit) | ||
| 68 | return MODE_VIRTUAL_Y; | ||
| 69 | |||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static enum drm_connector_status | ||
| 74 | udl_detect(struct drm_connector *connector, bool force) | ||
| 75 | { | ||
| 76 | struct udl_device *udl = to_udl(connector->dev); | ||
| 77 | struct udl_drm_connector *udl_connector = | ||
| 78 | container_of(connector, | ||
| 79 | struct udl_drm_connector, | ||
| 80 | connector); | ||
| 81 | |||
| 82 | /* cleanup previous edid */ | ||
| 83 | if (udl_connector->edid != NULL) { | ||
| 84 | kfree(udl_connector->edid); | ||
| 85 | udl_connector->edid = NULL; | ||
| 86 | } | ||
| 87 | |||
| 88 | udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); | ||
| 89 | if (!udl_connector->edid) | ||
| 90 | return connector_status_disconnected; | ||
| 91 | |||
| 92 | return connector_status_connected; | ||
| 93 | } | ||
| 94 | |||
| 95 | static void udl_connector_destroy(struct drm_connector *connector) | ||
| 96 | { | ||
| 97 | struct udl_drm_connector *udl_connector = | ||
| 98 | container_of(connector, | ||
| 99 | struct udl_drm_connector, | ||
| 100 | connector); | ||
| 101 | |||
| 102 | drm_connector_cleanup(connector); | ||
| 103 | kfree(udl_connector->edid); | ||
| 104 | kfree(connector); | ||
| 105 | } | ||
| 106 | |||
| 107 | static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { | ||
| 108 | .get_modes = udl_get_modes, | ||
| 109 | .mode_valid = udl_mode_valid, | ||
| 110 | }; | ||
| 111 | |||
| 112 | static const struct drm_connector_funcs udl_connector_funcs = { | ||
| 113 | .reset = drm_atomic_helper_connector_reset, | ||
| 114 | .detect = udl_detect, | ||
| 115 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 116 | .destroy = udl_connector_destroy, | ||
| 117 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
| 118 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
| 119 | }; | ||
| 120 | |||
| 121 | struct drm_connector *udl_connector_init(struct drm_device *dev) | ||
| 122 | { | ||
| 123 | struct udl_drm_connector *udl_connector; | ||
| 124 | struct drm_connector *connector; | ||
| 125 | |||
| 126 | udl_connector = kzalloc(sizeof(struct udl_drm_connector), GFP_KERNEL); | ||
| 127 | if (!udl_connector) | ||
| 128 | return ERR_PTR(-ENOMEM); | ||
| 129 | |||
| 130 | connector = &udl_connector->connector; | ||
| 131 | drm_connector_init(dev, connector, &udl_connector_funcs, | ||
| 132 | DRM_MODE_CONNECTOR_VGA); | ||
| 133 | drm_connector_helper_add(connector, &udl_connector_helper_funcs); | ||
| 134 | |||
| 135 | connector->polled = DRM_CONNECTOR_POLL_HPD | | ||
| 136 | DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; | ||
| 137 | |||
| 138 | return connector; | ||
| 139 | } | ||
| @@ -1,15 +0,0 @@ | |||
| 1 | #ifndef __UDL_CONNECTOR_H__ | ||
| 2 | #define __UDL_CONNECTOR_H__ | ||
| 3 | |||
| 4 | #include <drm/drm_crtc.h> | ||
| 5 | |||
| 6 | struct edid; | ||
| 7 | |||
| 8 | struct udl_drm_connector { | ||
| 9 | struct drm_connector connector; | ||
| 10 | /* last udl_detect edid */ | ||
| 11 | struct edid *edid; | ||
| 12 | }; | ||
| 13 | |||
| 14 | |||
| 15 | #endif //__UDL_CONNECTOR_H__ | ||
| @@ -14,10 +14,13 @@ · 13 unmodified lines | |||
| 14 | #include <linux/mm_types.h> | 14 | #include <linux/mm_types.h> |
| 15 | #include <linux/usb.h> | 15 | #include <linux/usb.h> |
| 16 | 16 | ||
| 17 | #include <drm/drm_connector.h> | ||
| 18 | #include <drm/drm_crtc.h> | ||
| 17 | #include <drm/drm_device.h> | 19 | #include <drm/drm_device.h> |
| 20 | #include <drm/drm_encoder.h> | ||
| 18 | #include <drm/drm_framebuffer.h> | 21 | #include <drm/drm_framebuffer.h> |
| 19 | #include <drm/drm_gem.h> | 22 | #include <drm/drm_gem.h> |
| 20 | #include <drm/drm_simple_kms_helper.h> | 23 | #include <drm/drm_plane.h> |
| 21 | 24 | ||
| 22 | struct drm_mode_create_dumb; | 25 | struct drm_mode_create_dumb; |
| 23 | 26 | ||
| @@ -46,21 +49,31 @@ struct urb_list { · 22 unmodified lines | |||
| 46 | size_t size; | 49 | size_t size; |
| 47 | }; | 50 | }; |
| 48 | 51 | ||
| 52 | struct udl_connector { | ||
| 53 | struct drm_connector connector; | ||
| 54 | /* last udl_detect edid */ | ||
| 55 | struct edid *edid; | ||
| 56 | }; | ||
| 57 | |||
| 58 | static inline struct udl_connector *to_udl_connector(struct drm_connector *connector) | ||
| 59 | { | ||
| 60 | return container_of(connector, struct udl_connector, connector); | ||
| 61 | } | ||
| 62 | |||
| 49 | struct udl_device { | 63 | struct udl_device { |
| 50 | struct drm_device drm; | 64 | struct drm_device drm; |
| 51 | struct device *dev; | 65 | struct device *dev; |
| 52 | struct device *dmadev; | 66 | struct device *dmadev; |
| 53 | 67 | ||
| 54 | struct drm_simple_display_pipe display_pipe; | 68 | struct drm_plane primary_plane; |
| 69 | struct drm_crtc crtc; | ||
| 70 | struct drm_encoder encoder; | ||
| 55 | 71 | ||
| 56 | struct mutex gem_lock; | 72 | struct mutex gem_lock; |
| 57 | 73 | ||
| 58 | int sku_pixel_limit; | 74 | int sku_pixel_limit; |
| 59 | 75 | ||
| 60 | struct urb_list urbs; | 76 | struct urb_list urbs; |
| 61 | |||
| 62 | char mode_buf[1024]; | ||
| 63 | uint32_t mode_buf_len; | ||
| 64 | }; | 77 | }; |
| 65 | 78 | ||
| 66 | #define to_udl(x) container_of(x, struct udl_device, drm) | 79 | #define to_udl(x) container_of(x, struct udl_device, drm) |
| @@ -89,23 +102,4 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, · 22 unmodified lines | |||
| 89 | int udl_drop_usb(struct drm_device *dev); | 102 | int udl_drop_usb(struct drm_device *dev); |
| 90 | int udl_select_std_channel(struct udl_device *udl); | 103 | int udl_select_std_channel(struct udl_device *udl); |
| 91 | 104 | ||
| 92 | #define CMD_WRITE_RAW8 "\xAF\x60" /**< 8 bit raw write command. */ | ||
| 93 | #define CMD_WRITE_RL8 "\xAF\x61" /**< 8 bit run length command. */ | ||
| 94 | #define CMD_WRITE_COPY8 "\xAF\x62" /**< 8 bit copy command. */ | ||
| 95 | #define CMD_WRITE_RLX8 "\xAF\x63" /**< 8 bit extended run length command. */ | ||
| 96 | |||
| 97 | #define CMD_WRITE_RAW16 "\xAF\x68" /**< 16 bit raw write command. */ | ||
| 98 | #define CMD_WRITE_RL16 "\xAF\x69" /**< 16 bit run length command. */ | ||
| 99 | #define CMD_WRITE_COPY16 "\xAF\x6A" /**< 16 bit copy command. */ | ||
| 100 | #define CMD_WRITE_RLX16 "\xAF\x6B" /**< 16 bit extended run length command. */ | ||
| 101 | |||
| 102 | /* On/Off for driving the DisplayLink framebuffer to the display */ | ||
| 103 | #define UDL_REG_BLANK_MODE 0x1f | ||
| 104 | |||
| 105 | #define UDL_BLANK_MODE_ON 0x00 /* hsync and vsync on, visible */ | ||
| 106 | #define UDL_BLANK_MODE_BLANKED 0x01 /* hsync and vsync on, blanked */ | ||
| 107 | #define UDL_BLANK_MODE_VSYNC_OFF 0x03 /* vsync off, blanked */ | ||
| 108 | #define UDL_BLANK_MODE_HSYNC_OFF 0x05 /* hsync off, blanked */ | ||
| 109 | #define UDL_BLANK_MODE_POWERDOWN 0x07 /* powered off; requires modeset */ | ||
| 110 | |||
| 111 | #endif | 105 | #endif |
| @@ -8,70 +8,91 @@ · 7 unmodified lines | |||
| 8 | * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com> | 8 | * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com> |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/bitfield.h> | ||
| 12 | |||
| 13 | #include <drm/drm_atomic.h> | ||
| 11 | #include <drm/drm_atomic_helper.h> | 14 | #include <drm/drm_atomic_helper.h> |
| 12 | #include <drm/drm_crtc_helper.h> | 15 | #include <drm/drm_crtc_helper.h> |
| 13 | #include <drm/drm_damage_helper.h> | 16 | #include <drm/drm_damage_helper.h> |
| 17 | #include <drm/drm_drv.h> | ||
| 18 | #include <drm/drm_edid.h> | ||
| 14 | #include <drm/drm_fourcc.h> | 19 | #include <drm/drm_fourcc.h> |
| 15 | #include <drm/drm_gem_atomic_helper.h> | 20 | #include <drm/drm_gem_atomic_helper.h> |
| 16 | #include <drm/drm_gem_framebuffer_helper.h> | 21 | #include <drm/drm_gem_framebuffer_helper.h> |
| 17 | #include <drm/drm_gem_shmem_helper.h> | 22 | #include <drm/drm_gem_shmem_helper.h> |
| 18 | #include <drm/drm_modeset_helper_vtables.h> | 23 | #include <drm/drm_modeset_helper_vtables.h> |
| 24 | #include <drm/drm_plane_helper.h> | ||
| 25 | #include <drm/drm_probe_helper.h> | ||
| 19 | #include <drm/drm_vblank.h> | 26 | #include <drm/drm_vblank.h> |
| 20 | 27 | ||
| 21 | #include "udl_drv.h" | 28 | #include "udl_drv.h" |
| 22 | 29 | #include "udl_proto.h" | |
| 23 | #define UDL_COLOR_DEPTH_16BPP 0 | ||
| 24 | 30 | ||
| 25 | /* | 31 | /* |
| 26 | * All DisplayLink bulk operations start with 0xAF, followed by specific code | 32 | * All DisplayLink bulk operations start with 0xaf (UDL_MSG_BULK), followed by |
| 27 | * All operations are written to buffers which then later get sent to device | 33 | * a specific command code. All operations are written to a command buffer, which |
| 34 | * the driver sends to the device. | ||
| 28 | */ | 35 | */ |
| 29 | static char *udl_set_register(char *buf, u8 reg, u8 val) | 36 | static char *udl_set_register(char *buf, u8 reg, u8 val) |
| 30 | { | 37 | { |
| 31 | *buf++ = 0xAF; | 38 | *buf++ = UDL_MSG_BULK; |
| 32 | *buf++ = 0x20; | 39 | *buf++ = UDL_CMD_WRITEREG; |
| 33 | *buf++ = reg; | 40 | *buf++ = reg; |
| 34 | *buf++ = val; | 41 | *buf++ = val; |
| 42 | |||
| 35 | return buf; | 43 | return buf; |
| 36 | } | 44 | } |
| 37 | 45 | ||
| 38 | static char *udl_vidreg_lock(char *buf) | 46 | static char *udl_vidreg_lock(char *buf) |
| 39 | { | 47 | { |
| 40 | return udl_set_register(buf, 0xFF, 0x00); | 48 | return udl_set_register(buf, UDL_REG_VIDREG, UDL_VIDREG_LOCK); |
| 41 | } | 49 | } |
| 42 | 50 | ||
| 43 | static char *udl_vidreg_unlock(char *buf) | 51 | static char *udl_vidreg_unlock(char *buf) |
| 44 | { | 52 | { |
| 45 | return udl_set_register(buf, 0xFF, 0xFF); | 53 | return udl_set_register(buf, UDL_REG_VIDREG, UDL_VIDREG_UNLOCK); |
| 46 | } | 54 | } |
| 47 | 55 | ||
| 48 | static char *udl_set_blank_mode(char *buf, u8 mode) | 56 | static char *udl_set_blank_mode(char *buf, u8 mode) |
| 49 | { | 57 | { |
| 50 | return udl_set_register(buf, UDL_REG_BLANK_MODE, mode); | 58 | return udl_set_register(buf, UDL_REG_BLANKMODE, mode); |
| 51 | } | 59 | } |
| 52 | 60 | ||
| 53 | static char *udl_set_color_depth(char *buf, u8 selection) | 61 | static char *udl_set_color_depth(char *buf, u8 selection) |
| 54 | { | 62 | { |
| 55 | return udl_set_register(buf, 0x00, selection); | 63 | return udl_set_register(buf, UDL_REG_COLORDEPTH, selection); |
| 56 | } | 64 | } |
| 57 | 65 | ||
| 58 | static char *udl_set_base16bpp(char *wrptr, u32 base) | 66 | static char *udl_set_base16bpp(char *buf, u32 base) |
| 59 | { | 67 | { |
| 60 | /* the base pointer is 16 bits wide, 0x20 is hi byte. */ | 68 | /* the base pointer is 24 bits wide, 0x20 is hi byte. */ |
| 61 | wrptr = udl_set_register(wrptr, 0x20, base >> 16); | 69 | u8 reg20 = FIELD_GET(UDL_BASE_ADDR2_MASK, base); |
| 62 | wrptr = udl_set_register(wrptr, 0x21, base >> 8); | 70 | u8 reg21 = FIELD_GET(UDL_BASE_ADDR1_MASK, base); |
| 63 | return udl_set_register(wrptr, 0x22, base); | 71 | u8 reg22 = FIELD_GET(UDL_BASE_ADDR0_MASK, base); |
| 72 | |||
| 73 | buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR2, reg20); | ||
| 74 | buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR1, reg21); | ||
| 75 | buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR0, reg22); | ||
| 76 | |||
| 77 | return buf; | ||
| 64 | } | 78 | } |
| 65 | 79 | ||
| 66 | /* | 80 | /* |
| 67 | * DisplayLink HW has separate 16bpp and 8bpp framebuffers. | 81 | * DisplayLink HW has separate 16bpp and 8bpp framebuffers. |
| 68 | * In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer | 82 | * In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer |
| 69 | */ | 83 | */ |
| 70 | static char *udl_set_base8bpp(char *wrptr, u32 base) | 84 | static char *udl_set_base8bpp(char *buf, u32 base) |
| 71 | { | 85 | { |
| 72 | wrptr = udl_set_register(wrptr, 0x26, base >> 16); | 86 | /* the base pointer is 24 bits wide, 0x26 is hi byte. */ |
| 73 | wrptr = udl_set_register(wrptr, 0x27, base >> 8); | 87 | u8 reg26 = FIELD_GET(UDL_BASE_ADDR2_MASK, base); |
| 74 | return udl_set_register(wrptr, 0x28, base); | 88 | u8 reg27 = FIELD_GET(UDL_BASE_ADDR1_MASK, base); |
| 89 | u8 reg28 = FIELD_GET(UDL_BASE_ADDR0_MASK, base); | ||
| 90 | |||
| 91 | buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR2, reg26); | ||
| 92 | buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR1, reg27); | ||
| 93 | buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR0, reg28); | ||
| 94 | |||
| 95 | return buf; | ||
| 75 | } | 96 | } |
| 76 | 97 | ||
| 77 | static char *udl_set_register_16(char *wrptr, u8 reg, u16 value) | 98 | static char *udl_set_register_16(char *wrptr, u8 reg, u16 value) |
| @@ -122,84 +143,46 @@ static char *udl_set_register_lfsr16(char *wrptr, u8 reg, u16 value) · 44 unmodified lines | |||
| 122 | } | 143 | } |
| 123 | 144 | ||
| 124 | /* | 145 | /* |
| 125 | * This takes a standard fbdev screeninfo struct and all of its monitor mode | 146 | * Takes a DRM display mode and converts it into the DisplayLink |
| 126 | * details and converts them into the DisplayLink equivalent register commands. | 147 | * equivalent register commands. |
| 127 | ERR(vreg(dev, 0x00, (color_depth == 16) ? 0 : 1)); | ||
| 128 | ERR(vreg_lfsr16(dev, 0x01, xDisplayStart)); | ||
| 129 | ERR(vreg_lfsr16(dev, 0x03, xDisplayEnd)); | ||
| 130 | ERR(vreg_lfsr16(dev, 0x05, yDisplayStart)); | ||
| 131 | ERR(vreg_lfsr16(dev, 0x07, yDisplayEnd)); | ||
| 132 | ERR(vreg_lfsr16(dev, 0x09, xEndCount)); | ||
| 133 | ERR(vreg_lfsr16(dev, 0x0B, hSyncStart)); | ||
| 134 | ERR(vreg_lfsr16(dev, 0x0D, hSyncEnd)); | ||
| 135 | ERR(vreg_big_endian(dev, 0x0F, hPixels)); | ||
| 136 | ERR(vreg_lfsr16(dev, 0x11, yEndCount)); | ||
| 137 | ERR(vreg_lfsr16(dev, 0x13, vSyncStart)); | ||
| 138 | ERR(vreg_lfsr16(dev, 0x15, vSyncEnd)); | ||
| 139 | ERR(vreg_big_endian(dev, 0x17, vPixels)); | ||
| 140 | ERR(vreg_little_endian(dev, 0x1B, pixelClock5KHz)); | ||
| 141 | |||
| 142 | ERR(vreg(dev, 0x1F, 0)); | ||
| 143 | |||
| 144 | ERR(vbuf(dev, WRITE_VIDREG_UNLOCK, DSIZEOF(WRITE_VIDREG_UNLOCK))); | ||
| 145 | */ | 148 | */ |
| 146 | static char *udl_set_vid_cmds(char *wrptr, struct drm_display_mode *mode) | 149 | static char *udl_set_display_mode(char *buf, struct drm_display_mode *mode) |
| 147 | { | 150 | { |
| 148 | u16 xds, yds; | 151 | u16 reg01 = mode->crtc_htotal - mode->crtc_hsync_start; |
| 149 | u16 xde, yde; | 152 | u16 reg03 = reg01 + mode->crtc_hdisplay; |
| 150 | u16 yec; | 153 | u16 reg05 = mode->crtc_vtotal - mode->crtc_vsync_start; |
| 151 | 154 | u16 reg07 = reg05 + mode->crtc_vdisplay; | |
| 152 | /* x display start */ | 155 | u16 reg09 = mode->crtc_htotal - 1; |
| 153 | xds = mode->crtc_htotal - mode->crtc_hsync_start; | 156 | u16 reg0b = 1; /* libdlo hardcodes hsync start to 1 */ |
| 154 | wrptr = udl_set_register_lfsr16(wrptr, 0x01, xds); | 157 | u16 reg0d = mode->crtc_hsync_end - mode->crtc_hsync_start + 1; |
| 155 | /* x display end */ | 158 | u16 reg0f = mode->hdisplay; |
| 156 | xde = xds + mode->crtc_hdisplay; | 159 | u16 reg11 = mode->crtc_vtotal; |
| 157 | wrptr = udl_set_register_lfsr16(wrptr, 0x03, xde); | 160 | u16 reg13 = 0; /* libdlo hardcodes vsync start to 0 */ |
| 158 | 161 | u16 reg15 = mode->crtc_vsync_end - mode->crtc_vsync_start; | |
| 159 | /* y display start */ | 162 | u16 reg17 = mode->crtc_vdisplay; |
| 160 | yds = mode->crtc_vtotal - mode->crtc_vsync_start; | 163 | u16 reg1b = mode->clock / 5; |
| 161 | wrptr = udl_set_register_lfsr16(wrptr, 0x05, yds); | 164 | |
| 162 | /* y display end */ | 165 | buf = udl_set_register_lfsr16(buf, UDL_REG_XDISPLAYSTART, reg01); |
| 163 | yde = yds + mode->crtc_vdisplay; | 166 | buf = udl_set_register_lfsr16(buf, UDL_REG_XDISPLAYEND, reg03); |
| 164 | wrptr = udl_set_register_lfsr16(wrptr, 0x07, yde); | 167 | buf = udl_set_register_lfsr16(buf, UDL_REG_YDISPLAYSTART, reg05); |
| 165 | 168 | buf = udl_set_register_lfsr16(buf, UDL_REG_YDISPLAYEND, reg07); | |
| 166 | /* x end count is active + blanking - 1 */ | 169 | buf = udl_set_register_lfsr16(buf, UDL_REG_XENDCOUNT, reg09); |
| 167 | wrptr = udl_set_register_lfsr16(wrptr, 0x09, | 170 | buf = udl_set_register_lfsr16(buf, UDL_REG_HSYNCSTART, reg0b); |
| 168 | mode->crtc_htotal - 1); | 171 | buf = udl_set_register_lfsr16(buf, UDL_REG_HSYNCEND, reg0d); |
| 172 | buf = udl_set_register_16(buf, UDL_REG_HPIXELS, reg0f); | ||
| 173 | buf = udl_set_register_lfsr16(buf, UDL_REG_YENDCOUNT, reg11); | ||
| 174 | buf = udl_set_register_lfsr16(buf, UDL_REG_VSYNCSTART, reg13); | ||
| 175 | buf = udl_set_register_lfsr16(buf, UDL_REG_VSYNCEND, reg15); | ||
| 176 | buf = udl_set_register_16(buf, UDL_REG_VPIXELS, reg17); | ||
| 177 | buf = udl_set_register_16be(buf, UDL_REG_PIXELCLOCK5KHZ, reg1b); | ||
| 169 | 178 | ||
| 170 | /* libdlo hardcodes hsync start to 1 */ | 179 | return buf; |
| 171 | wrptr = udl_set_register_lfsr16(wrptr, 0x0B, 1); | ||
| 172 | |||
| 173 | /* hsync end is width of sync pulse + 1 */ | ||
| 174 | wrptr = udl_set_register_lfsr16(wrptr, 0x0D, | ||
| 175 | mode->crtc_hsync_end - mode->crtc_hsync_start + 1); | ||
| 176 | |||
| 177 | /* hpixels is active pixels */ | ||
| 178 | wrptr = udl_set_register_16(wrptr, 0x0F, mode->hdisplay); | ||
| 179 | |||
| 180 | /* yendcount is vertical active + vertical blanking */ | ||
| 181 | yec = mode->crtc_vtotal; | ||
| 182 | wrptr = udl_set_register_lfsr16(wrptr, 0x11, yec); | ||
| 183 | |||
| 184 | /* libdlo hardcodes vsync start to 0 */ | ||
| 185 | wrptr = udl_set_register_lfsr16(wrptr, 0x13, 0); | ||
| 186 | |||
| 187 | /* vsync end is width of vsync pulse */ | ||
| 188 | wrptr = udl_set_register_lfsr16(wrptr, 0x15, mode->crtc_vsync_end - mode->crtc_vsync_start); | ||
| 189 | |||
| 190 | /* vpixels is active pixels */ | ||
| 191 | wrptr = udl_set_register_16(wrptr, 0x17, mode->crtc_vdisplay); | ||
| 192 | |||
| 193 | wrptr = udl_set_register_16be(wrptr, 0x1B, | ||
| 194 | mode->clock / 5); | ||
| 195 | |||
| 196 | return wrptr; | ||
| 197 | } | 180 | } |
| 198 | 181 | ||
| 199 | static char *udl_dummy_render(char *wrptr) | 182 | static char *udl_dummy_render(char *wrptr) |
| 200 | { | 183 | { |
| 201 | *wrptr++ = 0xAF; | 184 | *wrptr++ = UDL_MSG_BULK; |
| 202 | *wrptr++ = 0x6A; /* copy */ | 185 | *wrptr++ = UDL_CMD_WRITECOPY16; |
| 203 | *wrptr++ = 0x00; /* from addr */ | 186 | *wrptr++ = 0x00; /* from addr */ |
| 204 | *wrptr++ = 0x00; | 187 | *wrptr++ = 0x00; |
| 205 | *wrptr++ = 0x00; | 188 | *wrptr++ = 0x00; |
| @@ -210,31 +193,6 @@ static char *udl_dummy_render(char *wrptr) · 4 unmodified lines | |||
| 210 | return wrptr; | 193 | return wrptr; |
| 211 | } | 194 | } |
| 212 | 195 | ||
| 213 | static int udl_crtc_write_mode_to_hw(struct drm_crtc *crtc) | ||
| 214 | { | ||
| 215 | struct drm_device *dev = crtc->dev; | ||
| 216 | struct udl_device *udl = to_udl(dev); | ||
| 217 | struct urb *urb; | ||
| 218 | char *buf; | ||
| 219 | int retval; | ||
| 220 | |||
| 221 | if (udl->mode_buf_len == 0) { | ||
| 222 | DRM_ERROR("No mode set\n"); | ||
| 223 | return -EINVAL; | ||
| 224 | } | ||
| 225 | |||
| 226 | urb = udl_get_urb(dev); | ||
| 227 | if (!urb) | ||
| 228 | return -ENOMEM; | ||
| 229 | |||
| 230 | buf = (char *)urb->transfer_buffer; | ||
| 231 | |||
| 232 | memcpy(buf, udl->mode_buf, udl->mode_buf_len); | ||
| 233 | retval = udl_submit_urb(dev, urb, udl->mode_buf_len); | ||
| 234 | DRM_DEBUG("write mode info %d\n", udl->mode_buf_len); | ||
| 235 | return retval; | ||
| 236 | } | ||
| 237 | |||
| 238 | static long udl_log_cpp(unsigned int cpp) | 196 | static long udl_log_cpp(unsigned int cpp) |
| 239 | { | 197 | { |
| 240 | if (WARN_ON(!is_power_of_2(cpp))) | 198 | if (WARN_ON(!is_power_of_2(cpp))) |
| @@ -258,15 +216,9 @@ static int udl_handle_damage(struct drm_framebuffer *fb, · 17 unmodified lines | |||
| 258 | return ret; | 216 | return ret; |
| 259 | log_bpp = ret; | 217 | log_bpp = ret; |
| 260 | 218 | ||
| 261 | ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); | ||
| 262 | if (ret) | ||
| 263 | return ret; | ||
| 264 | |||
| 265 | urb = udl_get_urb(dev); | 219 | urb = udl_get_urb(dev); |
| 266 | if (!urb) { | 220 | if (!urb) |
| 267 | ret = -ENOMEM; | 221 | return -ENOMEM; |
| 268 | goto out_drm_gem_fb_end_cpu_access; | ||
| 269 | } | ||
| 270 | cmd = urb->transfer_buffer; | 222 | cmd = urb->transfer_buffer; |
| 271 | 223 | ||
| 272 | for (i = clip->y1; i < clip->y2; i++) { | 224 | for (i = clip->y1; i < clip->y2; i++) { |
| @@ -278,145 +230,339 @@ static int udl_handle_damage(struct drm_framebuffer *fb, · 5 unmodified lines | |||
| 278 | &cmd, byte_offset, dev_byte_offset, | 230 | &cmd, byte_offset, dev_byte_offset, |
| 279 | byte_width); | 231 | byte_width); |
| 280 | if (ret) | 232 | if (ret) |
| 281 | goto out_drm_gem_fb_end_cpu_access; | 233 | return ret; |
| 282 | } | 234 | } |
| 283 | 235 | ||
| 284 | if (cmd > (char *)urb->transfer_buffer) { | 236 | if (cmd > (char *)urb->transfer_buffer) { |
| 285 | /* Send partial buffer remaining before exiting */ | 237 | /* Send partial buffer remaining before exiting */ |
| 286 | int len; | 238 | int len; |
| 287 | if (cmd < (char *)urb->transfer_buffer + urb->transfer_buffer_length) | 239 | if (cmd < (char *)urb->transfer_buffer + urb->transfer_buffer_length) |
| 288 | *cmd++ = 0xAF; | 240 | *cmd++ = UDL_MSG_BULK; |
| 289 | len = cmd - (char *)urb->transfer_buffer; | 241 | len = cmd - (char *)urb->transfer_buffer; |
| 290 | ret = udl_submit_urb(dev, urb, len); | 242 | ret = udl_submit_urb(dev, urb, len); |
| 291 | } else { | 243 | } else { |
| 292 | udl_urb_completion(urb); | 244 | udl_urb_completion(urb); |
| 293 | } | 245 | } |
| 294 | 246 | ||
| 295 | ret = 0; | 247 | return 0; |
| 296 | |||
| 297 | out_drm_gem_fb_end_cpu_access: | ||
| 298 | drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); | ||
| 299 | return ret; | ||
| 300 | } | 248 | } |
| 301 | 249 | ||
| 302 | /* | 250 | /* |
| 303 | * Simple display pipeline | 251 | * Primary plane |
| 304 | */ | 252 | */ |
| 305 | 253 | ||
| 306 | static const uint32_t udl_simple_display_pipe_formats[] = { | 254 | static const uint32_t udl_primary_plane_formats[] = { |
| 307 | DRM_FORMAT_RGB565, | 255 | DRM_FORMAT_RGB565, |
| 308 | DRM_FORMAT_XRGB8888, | 256 | DRM_FORMAT_XRGB8888, |
| 309 | }; | 257 | }; |
| 310 | 258 | ||
| 311 | static enum drm_mode_status | 259 | static const uint64_t udl_primary_plane_fmtmods[] = { |
| 312 | udl_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, | 260 | DRM_FORMAT_MOD_LINEAR, |
| 313 | const struct drm_display_mode *mode) | 261 | DRM_FORMAT_MOD_INVALID |
| 262 | }; | ||
| 263 | |||
| 264 | static void udl_primary_plane_helper_atomic_update(struct drm_plane *plane, | ||
| 265 | struct drm_atomic_state *state) | ||
| 314 | { | 266 | { |
| 315 | return MODE_OK; | 267 | struct drm_device *dev = plane->dev; |
| 268 | struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); | ||
| 269 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); | ||
| 270 | struct drm_framebuffer *fb = plane_state->fb; | ||
| 271 | struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); | ||
| 272 | struct drm_atomic_helper_damage_iter iter; | ||
| 273 | struct drm_rect damage; | ||
| 274 | int ret, idx; | ||
| 275 | |||
| 276 | if (!fb) | ||
| 277 | return; /* no framebuffer; plane is disabled */ | ||
| 278 | |||
| 279 | ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); | ||
| 280 | if (ret) | ||
| 281 | return; | ||
| 282 | |||
| 283 | if (!drm_dev_enter(dev, &idx)) | ||
| 284 | goto out_drm_gem_fb_end_cpu_access; | ||
| 285 | |||
| 286 | drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); | ||
| 287 | drm_atomic_for_each_plane_damage(&iter, &damage) { | ||
| 288 | udl_handle_damage(fb, &shadow_plane_state->data[0], &damage); | ||
| 289 | } | ||
| 290 | |||
| 291 | drm_dev_exit(idx); | ||
| 292 | |||
| 293 | out_drm_gem_fb_end_cpu_access: | ||
| 294 | drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); | ||
| 295 | } | ||
| 296 | |||
| 297 | static const struct drm_plane_helper_funcs udl_primary_plane_helper_funcs = { | ||
| 298 | DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, | ||
| 299 | .atomic_check = drm_plane_helper_atomic_check, | ||
| 300 | .atomic_update = udl_primary_plane_helper_atomic_update, | ||
| 301 | }; | ||
| 302 | |||
| 303 | static const struct drm_plane_funcs udl_primary_plane_funcs = { | ||
| 304 | .update_plane = drm_atomic_helper_update_plane, | ||
| 305 | .disable_plane = drm_atomic_helper_disable_plane, | ||
| 306 | .destroy = drm_plane_cleanup, | ||
| 307 | DRM_GEM_SHADOW_PLANE_FUNCS, | ||
| 308 | }; | ||
| 309 | |||
| 310 | /* | ||
| 311 | * CRTC | ||
| 312 | */ | ||
| 313 | |||
| 314 | static int udl_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) | ||
| 315 | { | ||
| 316 | struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); | ||
| 317 | |||
| 318 | if (!new_crtc_state->enable) | ||
| 319 | return 0; | ||
| 320 | |||
| 321 | return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); | ||
| 316 | } | 322 | } |
| 317 | 323 | ||
| 318 | static void | 324 | static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) |
| 319 | udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, | ||
| 320 | struct drm_crtc_state *crtc_state, | ||
| 321 | struct drm_plane_state *plane_state) | ||
| 322 | { | 325 | { |
| 323 | struct drm_crtc *crtc = &pipe->crtc; | ||
| 324 | struct drm_device *dev = crtc->dev; | 326 | struct drm_device *dev = crtc->dev; |
| 325 | struct drm_framebuffer *fb = plane_state->fb; | 327 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); |
| 326 | struct udl_device *udl = to_udl(dev); | ||
| 327 | struct drm_display_mode *mode = &crtc_state->mode; | 328 | struct drm_display_mode *mode = &crtc_state->mode; |
| 328 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); | 329 | struct urb *urb; |
| 329 | struct drm_rect clip = DRM_RECT_INIT(0, 0, fb->width, fb->height); | ||
| 330 | char *buf; | 330 | char *buf; |
| 331 | char *wrptr; | 331 | int idx; |
| 332 | int color_depth = UDL_COLOR_DEPTH_16BPP; | ||
| 333 | 332 | ||
| 334 | buf = (char *)udl->mode_buf; | 333 | if (!drm_dev_enter(dev, &idx)) |
| 334 | return; | ||
| 335 | 335 | ||
| 336 | /* This first section has to do with setting the base address on the | 336 | urb = udl_get_urb(dev); |
| 337 | * controller associated with the display. There are 2 base | 337 | if (!urb) |
| 338 | * pointers, currently, we only use the 16 bpp segment. | 338 | goto out; |
| 339 | */ | 339 | |
| 340 | wrptr = udl_vidreg_lock(buf); | 340 | buf = (char *)urb->transfer_buffer; |
| 341 | wrptr = udl_set_color_depth(wrptr, color_depth); | 341 | buf = udl_vidreg_lock(buf); |
| 342 | buf = udl_set_color_depth(buf, UDL_COLORDEPTH_16BPP); | ||
| 342 | /* set base for 16bpp segment to 0 */ | 343 | /* set base for 16bpp segment to 0 */ |
| 343 | wrptr = udl_set_base16bpp(wrptr, 0); | 344 | buf = udl_set_base16bpp(buf, 0); |
| 344 | /* set base for 8bpp segment to end of fb */ | 345 | /* set base for 8bpp segment to end of fb */ |
| 345 | wrptr = udl_set_base8bpp(wrptr, 2 * mode->vdisplay * mode->hdisplay); | 346 | buf = udl_set_base8bpp(buf, 2 * mode->vdisplay * mode->hdisplay); |
| 346 | 347 | buf = udl_set_display_mode(buf, mode); | |
| 347 | wrptr = udl_set_vid_cmds(wrptr, mode); | 348 | buf = udl_set_blank_mode(buf, UDL_BLANKMODE_ON); |
| 348 | wrptr = udl_set_blank_mode(wrptr, UDL_BLANK_MODE_ON); | 349 | buf = udl_vidreg_unlock(buf); |
| 349 | wrptr = udl_vidreg_unlock(wrptr); | 350 | buf = udl_dummy_render(buf); |
| 350 | |||
| 351 | wrptr = udl_dummy_render(wrptr); | ||
| 352 | |||
| 353 | udl->mode_buf_len = wrptr - buf; | ||
| 354 | 351 | ||
| 355 | udl_handle_damage(fb, &shadow_plane_state->data[0], &clip); | 352 | udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); |
| 356 | 353 | ||
| 357 | /* enable display */ | 354 | out: |
| 358 | udl_crtc_write_mode_to_hw(crtc); | 355 | drm_dev_exit(idx); |
| 359 | } | 356 | } |
| 360 | 357 | ||
| 361 | static void | 358 | static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) |
| 362 | udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) | ||
| 363 | { | 359 | { |
| 364 | struct drm_crtc *crtc = &pipe->crtc; | ||
| 365 | struct drm_device *dev = crtc->dev; | 360 | struct drm_device *dev = crtc->dev; |
| 366 | struct urb *urb; | 361 | struct urb *urb; |
| 367 | char *buf; | 362 | char *buf; |
| 363 | int idx; | ||
| 364 | |||
| 365 | if (!drm_dev_enter(dev, &idx)) | ||
| 366 | return; | ||
| 368 | 367 | ||
| 369 | urb = udl_get_urb(dev); | 368 | urb = udl_get_urb(dev); |
| 370 | if (!urb) | 369 | if (!urb) |
| 371 | return; | 370 | goto out; |
| 372 | 371 | ||
| 373 | buf = (char *)urb->transfer_buffer; | 372 | buf = (char *)urb->transfer_buffer; |
| 374 | buf = udl_vidreg_lock(buf); | 373 | buf = udl_vidreg_lock(buf); |
| 375 | buf = udl_set_blank_mode(buf, UDL_BLANK_MODE_POWERDOWN); | 374 | buf = udl_set_blank_mode(buf, UDL_BLANKMODE_POWERDOWN); |
| 376 | buf = udl_vidreg_unlock(buf); | 375 | buf = udl_vidreg_unlock(buf); |
| 377 | buf = udl_dummy_render(buf); | 376 | buf = udl_dummy_render(buf); |
| 378 | 377 | ||
| 379 | udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); | 378 | udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); |
| 379 | |||
| 380 | out: | ||
| 381 | drm_dev_exit(idx); | ||
| 382 | } | ||
| 383 | |||
| 384 | static const struct drm_crtc_helper_funcs udl_crtc_helper_funcs = { | ||
| 385 | .atomic_check = udl_crtc_helper_atomic_check, | ||
| 386 | .atomic_enable = udl_crtc_helper_atomic_enable, | ||
| 387 | .atomic_disable = udl_crtc_helper_atomic_disable, | ||
| 388 | }; | ||
| 389 | |||
| 390 | static const struct drm_crtc_funcs udl_crtc_funcs = { | ||
| 391 | .reset = drm_atomic_helper_crtc_reset, | ||
| 392 | .destroy = drm_crtc_cleanup, | ||
| 393 | .set_config = drm_atomic_helper_set_config, | ||
| 394 | .page_flip = drm_atomic_helper_page_flip, | ||
| 395 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | ||
| 396 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | ||
| 397 | }; | ||
| 398 | |||
| 399 | /* | ||
| 400 | * Encoder | ||
| 401 | */ | ||
| 402 | |||
| 403 | static const struct drm_encoder_funcs udl_encoder_funcs = { | ||
| 404 | .destroy = drm_encoder_cleanup, | ||
| 405 | }; | ||
| 406 | |||
| 407 | /* | ||
| 408 | * Connector | ||
| 409 | */ | ||
| 410 | |||
| 411 | static int udl_connector_helper_get_modes(struct drm_connector *connector) | ||
| 412 | { | ||
| 413 | struct udl_connector *udl_connector = to_udl_connector(connector); | ||
| 414 | |||
| 415 | drm_connector_update_edid_property(connector, udl_connector->edid); | ||
| 416 | if (udl_connector->edid) | ||
| 417 | return drm_add_edid_modes(connector, udl_connector->edid); | ||
| 418 | |||
| 419 | return 0; | ||
| 380 | } | 420 | } |
| 381 | 421 | ||
| 382 | static void | 422 | static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { |
| 383 | udl_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, | 423 | .get_modes = udl_connector_helper_get_modes, |
| 384 | struct drm_plane_state *old_plane_state) | 424 | }; |
| 425 | |||
| 426 | static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) | ||
| 385 | { | 427 | { |
| 386 | struct drm_plane_state *state = pipe->plane.state; | 428 | struct udl_device *udl = data; |
| 387 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); | 429 | struct drm_device *dev = &udl->drm; |
| 388 | struct drm_framebuffer *fb = state->fb; | 430 | struct usb_device *udev = udl_to_usb_device(udl); |
| 389 | struct drm_rect rect; | 431 | u8 *read_buff; |
| 432 | int ret; | ||
| 433 | size_t i; | ||
| 390 | 434 | ||
| 391 | if (!fb) | 435 | read_buff = kmalloc(2, GFP_KERNEL); |
| 392 | return; | 436 | if (!read_buff) |
| 437 | return -ENOMEM; | ||
| 438 | |||
| 439 | for (i = 0; i < len; i++) { | ||
| 440 | int bval = (i + block * EDID_LENGTH) << 8; | ||
| 441 | |||
| 442 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | ||
| 443 | 0x02, (0x80 | (0x02 << 5)), bval, | ||
| 444 | 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); | ||
| 445 | if (ret < 0) { | ||
| 446 | drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); | ||
| 447 | goto err_kfree; | ||
| 448 | } else if (ret < 1) { | ||
| 449 | ret = -EIO; | ||
| 450 | drm_err(dev, "Read EDID byte %zu failed\n", i); | ||
| 451 | goto err_kfree; | ||
| 452 | } | ||
| 453 | |||
| 454 | buf[i] = read_buff[1]; | ||
| 455 | } | ||
| 456 | |||
| 457 | kfree(read_buff); | ||
| 458 | |||
| 459 | return 0; | ||
| 460 | |||
| 461 | err_kfree: | ||
| 462 | kfree(read_buff); | ||
| 463 | return ret; | ||
| 464 | } | ||
| 465 | |||
| 466 | static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) | ||
| 467 | { | ||
| 468 | struct drm_device *dev = connector->dev; | ||
| 469 | struct udl_device *udl = to_udl(dev); | ||
| 470 | struct udl_connector *udl_connector = to_udl_connector(connector); | ||
| 471 | enum drm_connector_status status = connector_status_disconnected; | ||
| 472 | int idx; | ||
| 473 | |||
| 474 | /* cleanup previous EDID */ | ||
| 475 | kfree(udl_connector->edid); | ||
| 476 | udl_connector->edid = NULL; | ||
| 477 | |||
| 478 | if (!drm_dev_enter(dev, &idx)) | ||
| 479 | return connector_status_disconnected; | ||
| 480 | |||
| 481 | udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); | ||
| 482 | if (udl_connector->edid) | ||
| 483 | status = connector_status_connected; | ||
| 484 | |||
| 485 | drm_dev_exit(idx); | ||
| 486 | |||
| 487 | return status; | ||
| 488 | } | ||
| 393 | 489 | ||
| 394 | if (drm_atomic_helper_damage_merged(old_plane_state, state, &rect)) | 490 | static void udl_connector_destroy(struct drm_connector *connector) |
| 395 | udl_handle_damage(fb, &shadow_plane_state->data[0], &rect); | 491 | { |
| 492 | struct udl_connector *udl_connector = to_udl_connector(connector); | ||
| 493 | |||
| 494 | drm_connector_cleanup(connector); | ||
| 495 | kfree(udl_connector->edid); | ||
| 496 | kfree(udl_connector); | ||
| 396 | } | 497 | } |
| 397 | 498 | ||
| 398 | static const struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs = { | 499 | static const struct drm_connector_funcs udl_connector_funcs = { |
| 399 | .mode_valid = udl_simple_display_pipe_mode_valid, | 500 | .reset = drm_atomic_helper_connector_reset, |
| 400 | .enable = udl_simple_display_pipe_enable, | 501 | .detect = udl_connector_detect, |
| 401 | .disable = udl_simple_display_pipe_disable, | 502 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 402 | .update = udl_simple_display_pipe_update, | 503 | .destroy = udl_connector_destroy, |
| 403 | DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, | 504 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
| 505 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
| 404 | }; | 506 | }; |
| 405 | 507 | ||
| 508 | struct drm_connector *udl_connector_init(struct drm_device *dev) | ||
| 509 | { | ||
| 510 | struct udl_connector *udl_connector; | ||
| 511 | struct drm_connector *connector; | ||
| 512 | int ret; | ||
| 513 | |||
| 514 | udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); | ||
| 515 | if (!udl_connector) | ||
| 516 | return ERR_PTR(-ENOMEM); | ||
| 517 | |||
| 518 | connector = &udl_connector->connector; | ||
| 519 | ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA); | ||
| 520 | if (ret) | ||
| 521 | goto err_kfree; | ||
| 522 | |||
| 523 | drm_connector_helper_add(connector, &udl_connector_helper_funcs); | ||
| 524 | |||
| 525 | connector->polled = DRM_CONNECTOR_POLL_HPD | | ||
| 526 | DRM_CONNECTOR_POLL_CONNECT | | ||
| 527 | DRM_CONNECTOR_POLL_DISCONNECT; | ||
| 528 | |||
| 529 | return connector; | ||
| 530 | |||
| 531 | err_kfree: | ||
| 532 | kfree(udl_connector); | ||
| 533 | return ERR_PTR(ret); | ||
| 534 | } | ||
| 535 | |||
| 406 | /* | 536 | /* |
| 407 | * Modesetting | 537 | * Modesetting |
| 408 | */ | 538 | */ |
| 409 | 539 | ||
| 410 | static const struct drm_mode_config_funcs udl_mode_funcs = { | 540 | static enum drm_mode_status udl_mode_config_mode_valid(struct drm_device *dev, |
| 541 | const struct drm_display_mode *mode) | ||
| 542 | { | ||
| 543 | struct udl_device *udl = to_udl(dev); | ||
| 544 | |||
| 545 | if (udl->sku_pixel_limit) { | ||
| 546 | if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit) | ||
| 547 | return MODE_MEM; | ||
| 548 | } | ||
| 549 | |||
| 550 | return MODE_OK; | ||
| 551 | } | ||
| 552 | |||
| 553 | static const struct drm_mode_config_funcs udl_mode_config_funcs = { | ||
| 411 | .fb_create = drm_gem_fb_create_with_dirty, | 554 | .fb_create = drm_gem_fb_create_with_dirty, |
| 555 | .mode_valid = udl_mode_config_mode_valid, | ||
| 412 | .atomic_check = drm_atomic_helper_check, | 556 | .atomic_check = drm_atomic_helper_check, |
| 413 | .atomic_commit = drm_atomic_helper_commit, | 557 | .atomic_commit = drm_atomic_helper_commit, |
| 414 | }; | 558 | }; |
| 415 | 559 | ||
| 416 | int udl_modeset_init(struct drm_device *dev) | 560 | int udl_modeset_init(struct drm_device *dev) |
| 417 | { | 561 | { |
| 418 | size_t format_count = ARRAY_SIZE(udl_simple_display_pipe_formats); | ||
| 419 | struct udl_device *udl = to_udl(dev); | 562 | struct udl_device *udl = to_udl(dev); |
| 563 | struct drm_plane *primary_plane; | ||
| 564 | struct drm_crtc *crtc; | ||
| 565 | struct drm_encoder *encoder; | ||
| 420 | struct drm_connector *connector; | 566 | struct drm_connector *connector; |
| 421 | int ret; | 567 | int ret; |
| 422 | 568 | ||
| @@ -426,28 +572,42 @@ int udl_modeset_init(struct drm_device *dev) · 3 unmodified lines | |||
| 426 | 572 | ||
| 427 | dev->mode_config.min_width = 640; | 573 | dev->mode_config.min_width = 640; |
| 428 | dev->mode_config.min_height = 480; | 574 | dev->mode_config.min_height = 480; |
| 429 | |||
| 430 | dev->mode_config.max_width = 2048; | 575 | dev->mode_config.max_width = 2048; |
| 431 | dev->mode_config.max_height = 2048; | 576 | dev->mode_config.max_height = 2048; |
| 432 | |||
| 433 | dev->mode_config.prefer_shadow = 0; | ||
| 434 | dev->mode_config.preferred_depth = 16; | 577 | dev->mode_config.preferred_depth = 16; |
| 578 | dev->mode_config.funcs = &udl_mode_config_funcs; | ||
| 579 | |||
| 580 | primary_plane = &udl->primary_plane; | ||
| 581 | ret = drm_universal_plane_init(dev, primary_plane, 0, | ||
| 582 | &udl_primary_plane_funcs, | ||
| 583 | udl_primary_plane_formats, | ||
| 584 | ARRAY_SIZE(udl_primary_plane_formats), | ||
| 585 | udl_primary_plane_fmtmods, | ||
| 586 | DRM_PLANE_TYPE_PRIMARY, NULL); | ||
| 587 | if (ret) | ||
| 588 | return ret; | ||
| 589 | drm_plane_helper_add(primary_plane, &udl_primary_plane_helper_funcs); | ||
| 590 | drm_plane_enable_fb_damage_clips(primary_plane); | ||
| 435 | 591 | ||
| 436 | dev->mode_config.funcs = &udl_mode_funcs; | 592 | crtc = &udl->crtc; |
| 593 | ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, | ||
| 594 | &udl_crtc_funcs, NULL); | ||
| 595 | if (ret) | ||
| 596 | return ret; | ||
| 597 | drm_crtc_helper_add(crtc, &udl_crtc_helper_funcs); | ||
| 598 | |||
| 599 | encoder = &udl->encoder; | ||
| 600 | ret = drm_encoder_init(dev, encoder, &udl_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL); | ||
| 601 | if (ret) | ||
| 602 | return ret; | ||
| 603 | encoder->possible_crtcs = drm_crtc_mask(crtc); | ||
| 437 | 604 | ||
| 438 | connector = udl_connector_init(dev); | 605 | connector = udl_connector_init(dev); |
| 439 | if (IS_ERR(connector)) | 606 | if (IS_ERR(connector)) |
| 440 | return PTR_ERR(connector); | 607 | return PTR_ERR(connector); |
| 441 | 608 | ret = drm_connector_attach_encoder(connector, encoder); | |
| 442 | format_count = ARRAY_SIZE(udl_simple_display_pipe_formats); | ||
| 443 | |||
| 444 | ret = drm_simple_display_pipe_init(dev, &udl->display_pipe, | ||
| 445 | &udl_simple_display_pipe_funcs, | ||
| 446 | udl_simple_display_pipe_formats, | ||
| 447 | format_count, NULL, connector); | ||
| 448 | if (ret) | 609 | if (ret) |
| 449 | return ret; | 610 | return ret; |
| 450 | drm_plane_enable_fb_damage_clips(&udl->display_pipe.plane); | ||
| 451 | 611 | ||
| 452 | drm_mode_config_reset(dev); | 612 | drm_mode_config_reset(dev); |
| 453 | 613 | ||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-only */ | ||
| 2 | |||
| 3 | #ifndef UDL_PROTO_H | ||
| 4 | #define UDL_PROTO_H | ||
| 5 | |||
| 6 | #include <linux/bits.h> | ||
| 7 | |||
| 8 | #define UDL_MSG_BULK 0xaf | ||
| 9 | |||
| 10 | /* Register access */ | ||
| 11 | #define UDL_CMD_WRITEREG 0x20 /* See register constants below */ | ||
| 12 | |||
| 13 | /* Framebuffer access */ | ||
| 14 | #define UDL_CMD_WRITERAW8 0x60 /* 8 bit raw write command. */ | ||
| 15 | #define UDL_CMD_WRITERL8 0x61 /* 8 bit run length command. */ | ||
| 16 | #define UDL_CMD_WRITECOPY8 0x62 /* 8 bit copy command. */ | ||
| 17 | #define UDL_CMD_WRITERLX8 0x63 /* 8 bit extended run length command. */ | ||
| 18 | #define UDL_CMD_WRITERAW16 0x68 /* 16 bit raw write command. */ | ||
| 19 | #define UDL_CMD_WRITERL16 0x69 /* 16 bit run length command. */ | ||
| 20 | #define UDL_CMD_WRITECOPY16 0x6a /* 16 bit copy command. */ | ||
| 21 | #define UDL_CMD_WRITERLX16 0x6b /* 16 bit extended run length command. */ | ||
| 22 | |||
| 23 | /* Color depth */ | ||
| 24 | #define UDL_REG_COLORDEPTH 0x00 | ||
| 25 | #define UDL_COLORDEPTH_16BPP 0 | ||
| 26 | #define UDL_COLORDEPTH_24BPP 1 | ||
| 27 | |||
| 28 | /* Display-mode settings */ | ||
| 29 | #define UDL_REG_XDISPLAYSTART 0x01 | ||
| 30 | #define UDL_REG_XDISPLAYEND 0x03 | ||
| 31 | #define UDL_REG_YDISPLAYSTART 0x05 | ||
| 32 | #define UDL_REG_YDISPLAYEND 0x07 | ||
| 33 | #define UDL_REG_XENDCOUNT 0x09 | ||
| 34 | #define UDL_REG_HSYNCSTART 0x0b | ||
| 35 | #define UDL_REG_HSYNCEND 0x0d | ||
| 36 | #define UDL_REG_HPIXELS 0x0f | ||
| 37 | #define UDL_REG_YENDCOUNT 0x11 | ||
| 38 | #define UDL_REG_VSYNCSTART 0x13 | ||
| 39 | #define UDL_REG_VSYNCEND 0x15 | ||
| 40 | #define UDL_REG_VPIXELS 0x17 | ||
| 41 | #define UDL_REG_PIXELCLOCK5KHZ 0x1b | ||
| 42 | |||
| 43 | /* On/Off for driving the DisplayLink framebuffer to the display */ | ||
| 44 | #define UDL_REG_BLANKMODE 0x1f | ||
| 45 | #define UDL_BLANKMODE_ON 0x00 /* hsync and vsync on, visible */ | ||
| 46 | #define UDL_BLANKMODE_BLANKED 0x01 /* hsync and vsync on, blanked */ | ||
| 47 | #define UDL_BLANKMODE_VSYNC_OFF 0x03 /* vsync off, blanked */ | ||
| 48 | #define UDL_BLANKMODE_HSYNC_OFF 0x05 /* hsync off, blanked */ | ||
| 49 | #define UDL_BLANKMODE_POWERDOWN 0x07 /* powered off; requires modeset */ | ||
| 50 | |||
| 51 | /* Framebuffer address */ | ||
| 52 | #define UDL_REG_BASE16BPP_ADDR2 0x20 | ||
| 53 | #define UDL_REG_BASE16BPP_ADDR1 0x21 | ||
| 54 | #define UDL_REG_BASE16BPP_ADDR0 0x22 | ||
| 55 | #define UDL_REG_BASE8BPP_ADDR2 0x26 | ||
| 56 | #define UDL_REG_BASE8BPP_ADDR1 0x27 | ||
| 57 | #define UDL_REG_BASE8BPP_ADDR0 0x28 | ||
| 58 | |||
| 59 | #define UDL_BASE_ADDR0_MASK GENMASK(7, 0) | ||
| 60 | #define UDL_BASE_ADDR1_MASK GENMASK(15, 8) | ||
| 61 | #define UDL_BASE_ADDR2_MASK GENMASK(23, 16) | ||
| 62 | |||
| 63 | /* Lock/unlock video registers */ | ||
| 64 | #define UDL_REG_VIDREG 0xff | ||
| 65 | #define UDL_VIDREG_LOCK 0x00 | ||
| 66 | #define UDL_VIDREG_UNLOCK 0xff | ||
| 67 | |||
| 68 | #endif | ||
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <asm/unaligned.h> | 10 | #include <asm/unaligned.h> |
| 11 | 11 | ||
| 12 | #include "udl_drv.h" | 12 | #include "udl_drv.h" |
| 13 | #include "udl_proto.h" | ||
| 13 | 14 | ||
| 14 | #define MAX_CMD_PIXELS 255 | 15 | #define MAX_CMD_PIXELS 255 |
| 15 | 16 | ||
| @@ -89,8 +90,8 @@ static void udl_compress_hline16( · 73 unmodified lines | |||
| 89 | const u8 *cmd_pixel_start, *cmd_pixel_end = NULL; | 90 | const u8 *cmd_pixel_start, *cmd_pixel_end = NULL; |
| 90 | uint16_t pixel_val16; | 91 | uint16_t pixel_val16; |
| 91 | 92 | ||
| 92 | *cmd++ = 0xaf; | 93 | *cmd++ = UDL_MSG_BULK; |
| 93 | *cmd++ = 0x6b; | 94 | *cmd++ = UDL_CMD_WRITERLX16; |
| 94 | *cmd++ = (uint8_t) ((dev_addr >> 16) & 0xFF); | 95 | *cmd++ = (uint8_t) ((dev_addr >> 16) & 0xFF); |
| 95 | *cmd++ = (uint8_t) ((dev_addr >> 8) & 0xFF); | 96 | *cmd++ = (uint8_t) ((dev_addr >> 8) & 0xFF); |
| 96 | *cmd++ = (uint8_t) ((dev_addr) & 0xFF); | 97 | *cmd++ = (uint8_t) ((dev_addr) & 0xFF); |
| @@ -152,7 +153,7 @@ static void udl_compress_hline16( · 55 unmodified lines | |||
| 152 | if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) { | 153 | if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) { |
| 153 | /* Fill leftover bytes with no-ops */ | 154 | /* Fill leftover bytes with no-ops */ |
| 154 | if (cmd_buffer_end > cmd) | 155 | if (cmd_buffer_end > cmd) |
| 155 | memset(cmd, 0xAF, cmd_buffer_end - cmd); | 156 | memset(cmd, UDL_MSG_BULK, cmd_buffer_end - cmd); |
| 156 | cmd = (uint8_t *) cmd_buffer_end; | 157 | cmd = (uint8_t *) cmd_buffer_end; |
| 157 | } | 158 | } |
| 158 | 159 | ||
| @@ -542,7 +542,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector) · 541 unmodified lines | |||
| 542 | new_state->base.max_bpc = 8; | 542 | new_state->base.max_bpc = 8; |
| 543 | new_state->base.max_requested_bpc = 8; | 543 | new_state->base.max_requested_bpc = 8; |
| 544 | new_state->output_format = VC4_HDMI_OUTPUT_RGB; | 544 | new_state->output_format = VC4_HDMI_OUTPUT_RGB; |
| 545 | drm_atomic_helper_connector_tv_reset(connector); | 545 | drm_atomic_helper_connector_tv_margins_reset(connector); |
| 546 | } | 546 | } |
| 547 | 547 | ||
| 548 | static struct drm_connector_state * | 548 | static struct drm_connector_state * |
| @@ -69,6 +69,7 @@ · 68 unmodified lines | |||
| 69 | #define VEC_CONFIG0_STD_MASK GENMASK(1, 0) | 69 | #define VEC_CONFIG0_STD_MASK GENMASK(1, 0) |
| 70 | #define VEC_CONFIG0_NTSC_STD 0 | 70 | #define VEC_CONFIG0_NTSC_STD 0 |
| 71 | #define VEC_CONFIG0_PAL_BDGHI_STD 1 | 71 | #define VEC_CONFIG0_PAL_BDGHI_STD 1 |
| 72 | #define VEC_CONFIG0_PAL_M_STD 2 | ||
| 72 | #define VEC_CONFIG0_PAL_N_STD 3 | 73 | #define VEC_CONFIG0_PAL_N_STD 3 |
| 73 | 74 | ||
| 74 | #define VEC_SCHPH 0x108 | 75 | #define VEC_SCHPH 0x108 |
| @@ -255,10 +256,9 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = { · 180 unmodified lines | |||
| 255 | .config1 = VEC_CONFIG1_C_CVBS_CVBS, | 256 | .config1 = VEC_CONFIG1_C_CVBS_CVBS, |
| 256 | }, | 257 | }, |
| 257 | [VC4_VEC_TV_MODE_PAL_M] = { | 258 | [VC4_VEC_TV_MODE_PAL_M] = { |
| 258 | .mode = &pal_mode, | 259 | .mode = &ntsc_mode, |
| 259 | .config0 = VEC_CONFIG0_PAL_BDGHI_STD, | 260 | .config0 = VEC_CONFIG0_PAL_M_STD, |
| 260 | .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ, | 261 | .config1 = VEC_CONFIG1_C_CVBS_CVBS, |
| 261 | .custom_freq = 0x223b61d1, | ||
| 262 | }, | 262 | }, |
| 263 | }; | 263 | }; |
| 264 | 264 | ||
| @@ -26,7 +26,8 @@ int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf) · 25 unmodified lines | |||
| 26 | if (umem_dmabuf->sgt) | 26 | if (umem_dmabuf->sgt) |
| 27 | goto wait_fence; | 27 | goto wait_fence; |
| 28 | 28 | ||
| 29 | sgt = dma_buf_map_attachment(umem_dmabuf->attach, DMA_BIDIRECTIONAL); | 29 | sgt = dma_buf_map_attachment_unlocked(umem_dmabuf->attach, |
| 30 | DMA_BIDIRECTIONAL); | ||
| 30 | if (IS_ERR(sgt)) | 31 | if (IS_ERR(sgt)) |
| 31 | return PTR_ERR(sgt); | 32 | return PTR_ERR(sgt); |
| 32 | 33 | ||
| @@ -102,8 +103,8 @@ void ib_umem_dmabuf_unmap_pages(struct ib_umem_dmabuf *umem_dmabuf) · 69 unmodified lines | |||
| 102 | umem_dmabuf->last_sg_trim = 0; | 103 | umem_dmabuf->last_sg_trim = 0; |
| 103 | } | 104 | } |
| 104 | 105 | ||
| 105 | dma_buf_unmap_attachment(umem_dmabuf->attach, umem_dmabuf->sgt, | 106 | dma_buf_unmap_attachment_unlocked(umem_dmabuf->attach, umem_dmabuf->sgt, |
| 106 | DMA_BIDIRECTIONAL); | 107 | DMA_BIDIRECTIONAL); |
| 107 | 108 | ||
| 108 | umem_dmabuf->sgt = NULL; | 109 | umem_dmabuf->sgt = NULL; |
| 109 | } | 110 | } |
| @@ -101,7 +101,7 @@ static void *vb2_dc_vaddr(struct vb2_buffer *vb, void *buf_priv) · 100 unmodified lines | |||
| 101 | if (buf->db_attach) { | 101 | if (buf->db_attach) { |
| 102 | struct iosys_map map; | 102 | struct iosys_map map; |
| 103 | 103 | ||
| 104 | if (!dma_buf_vmap(buf->db_attach->dmabuf, &map)) | 104 | if (!dma_buf_vmap_unlocked(buf->db_attach->dmabuf, &map)) |
| 105 | buf->vaddr = map.vaddr; | 105 | buf->vaddr = map.vaddr; |
| 106 | 106 | ||
| 107 | return buf->vaddr; | 107 | return buf->vaddr; |
| @@ -382,18 +382,12 @@ static struct sg_table *vb2_dc_dmabuf_ops_map( · 274 unmodified lines | |||
| 382 | struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) | 382 | struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) |
| 383 | { | 383 | { |
| 384 | struct vb2_dc_attachment *attach = db_attach->priv; | 384 | struct vb2_dc_attachment *attach = db_attach->priv; |
| 385 | /* stealing dmabuf mutex to serialize map/unmap operations */ | ||
| 386 | struct mutex *lock = &db_attach->dmabuf->lock; | ||
| 387 | struct sg_table *sgt; | 385 | struct sg_table *sgt; |
| 388 | 386 | ||
| 389 | mutex_lock(lock); | ||
| 390 | |||
| 391 | sgt = &attach->sgt; | 387 | sgt = &attach->sgt; |
| 392 | /* return previously mapped sg table */ | 388 | /* return previously mapped sg table */ |
| 393 | if (attach->dma_dir == dma_dir) { | 389 | if (attach->dma_dir == dma_dir) |
| 394 | mutex_unlock(lock); | ||
| 395 | return sgt; | 390 | return sgt; |
| 396 | } | ||
| 397 | 391 | ||
| 398 | /* release any previous cache */ | 392 | /* release any previous cache */ |
| 399 | if (attach->dma_dir != DMA_NONE) { | 393 | if (attach->dma_dir != DMA_NONE) { |
| @@ -409,14 +403,11 @@ static struct sg_table *vb2_dc_dmabuf_ops_map( · 9 unmodified lines | |||
| 409 | if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, | 403 | if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, |
| 410 | DMA_ATTR_SKIP_CPU_SYNC)) { | 404 | DMA_ATTR_SKIP_CPU_SYNC)) { |
| 411 | pr_err("failed to map scatterlist\n"); | 405 | pr_err("failed to map scatterlist\n"); |
| 412 | mutex_unlock(lock); | ||
| 413 | return ERR_PTR(-EIO); | 406 | return ERR_PTR(-EIO); |
| 414 | } | 407 | } |
| 415 | 408 | ||
| 416 | attach->dma_dir = dma_dir; | 409 | attach->dma_dir = dma_dir; |
| 417 | 410 | ||
| 418 | mutex_unlock(lock); | ||
| 419 | |||
| 420 | return sgt; | 411 | return sgt; |
| 421 | } | 412 | } |
| 422 | 413 | ||
| @@ -711,7 +702,7 @@ static int vb2_dc_map_dmabuf(void *mem_priv) · 288 unmodified lines | |||
| 711 | } | 702 | } |
| 712 | 703 | ||
| 713 | /* get the associated scatterlist for this buffer */ | 704 | /* get the associated scatterlist for this buffer */ |
| 714 | sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); | 705 | sgt = dma_buf_map_attachment_unlocked(buf->db_attach, buf->dma_dir); |
| 715 | if (IS_ERR(sgt)) { | 706 | if (IS_ERR(sgt)) { |
| 716 | pr_err("Error getting dmabuf scatterlist\n"); | 707 | pr_err("Error getting dmabuf scatterlist\n"); |
| 717 | return -EINVAL; | 708 | return -EINVAL; |
| @@ -722,7 +713,8 @@ static int vb2_dc_map_dmabuf(void *mem_priv) · 4 unmodified lines | |||
| 722 | if (contig_size < buf->size) { | 713 | if (contig_size < buf->size) { |
| 723 | pr_err("contiguous chunk is too small %lu/%lu\n", | 714 | pr_err("contiguous chunk is too small %lu/%lu\n", |
| 724 | contig_size, buf->size); | 715 | contig_size, buf->size); |
| 725 | dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); | 716 | dma_buf_unmap_attachment_unlocked(buf->db_attach, sgt, |
| 717 | buf->dma_dir); | ||
| 726 | return -EFAULT; | 718 | return -EFAULT; |
| 727 | } | 719 | } |
| 728 | 720 | ||
| @@ -750,10 +742,10 @@ static void vb2_dc_unmap_dmabuf(void *mem_priv) · 21 unmodified lines | |||
| 750 | } | 742 | } |
| 751 | 743 | ||
| 752 | if (buf->vaddr) { | 744 | if (buf->vaddr) { |
| 753 | dma_buf_vunmap(buf->db_attach->dmabuf, &map); | 745 | dma_buf_vunmap_unlocked(buf->db_attach->dmabuf, &map); |
| 754 | buf->vaddr = NULL; | 746 | buf->vaddr = NULL; |
| 755 | } | 747 | } |
| 756 | dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); | 748 | dma_buf_unmap_attachment_unlocked(buf->db_attach, sgt, buf->dma_dir); |
| 757 | 749 | ||
| 758 | buf->dma_addr = 0; | 750 | buf->dma_addr = 0; |
| 759 | buf->dma_sgt = NULL; | 751 | buf->dma_sgt = NULL; |
| @@ -309,7 +309,7 @@ static void *vb2_dma_sg_vaddr(struct vb2_buffer *vb, void *buf_priv) · 308 unmodified lines | |||
| 309 | 309 | ||
| 310 | if (!buf->vaddr) { | 310 | if (!buf->vaddr) { |
| 311 | if (buf->db_attach) { | 311 | if (buf->db_attach) { |
| 312 | ret = dma_buf_vmap(buf->db_attach->dmabuf, &map); | 312 | ret = dma_buf_vmap_unlocked(buf->db_attach->dmabuf, &map); |
| 313 | buf->vaddr = ret ? NULL : map.vaddr; | 313 | buf->vaddr = ret ? NULL : map.vaddr; |
| 314 | } else { | 314 | } else { |
| 315 | buf->vaddr = vm_map_ram(buf->pages, buf->num_pages, -1); | 315 | buf->vaddr = vm_map_ram(buf->pages, buf->num_pages, -1); |
| @@ -424,18 +424,12 @@ static struct sg_table *vb2_dma_sg_dmabuf_ops_map( · 108 unmodified lines | |||
| 424 | struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) | 424 | struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) |
| 425 | { | 425 | { |
| 426 | struct vb2_dma_sg_attachment *attach = db_attach->priv; | 426 | struct vb2_dma_sg_attachment *attach = db_attach->priv; |
| 427 | /* stealing dmabuf mutex to serialize map/unmap operations */ | ||
| 428 | struct mutex *lock = &db_attach->dmabuf->lock; | ||
| 429 | struct sg_table *sgt; | 427 | struct sg_table *sgt; |
| 430 | 428 | ||
| 431 | mutex_lock(lock); | ||
| 432 | |||
| 433 | sgt = &attach->sgt; | 429 | sgt = &attach->sgt; |
| 434 | /* return previously mapped sg table */ | 430 | /* return previously mapped sg table */ |
| 435 | if (attach->dma_dir == dma_dir) { | 431 | if (attach->dma_dir == dma_dir) |
| 436 | mutex_unlock(lock); | ||
| 437 | return sgt; | 432 | return sgt; |
| 438 | } | ||
| 439 | 433 | ||
| 440 | /* release any previous cache */ | 434 | /* release any previous cache */ |
| 441 | if (attach->dma_dir != DMA_NONE) { | 435 | if (attach->dma_dir != DMA_NONE) { |
| @@ -446,14 +440,11 @@ static struct sg_table *vb2_dma_sg_dmabuf_ops_map( · 4 unmodified lines | |||
| 446 | /* mapping to the client with new direction */ | 440 | /* mapping to the client with new direction */ |
| 447 | if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) { | 441 | if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) { |
| 448 | pr_err("failed to map scatterlist\n"); | 442 | pr_err("failed to map scatterlist\n"); |
| 449 | mutex_unlock(lock); | ||
| 450 | return ERR_PTR(-EIO); | 443 | return ERR_PTR(-EIO); |
| 451 | } | 444 | } |
| 452 | 445 | ||
| 453 | attach->dma_dir = dma_dir; | 446 | attach->dma_dir = dma_dir; |
| 454 | 447 | ||
| 455 | mutex_unlock(lock); | ||
| 456 | |||
| 457 | return sgt; | 448 | return sgt; |
| 458 | } | 449 | } |
| 459 | 450 | ||
| @@ -565,7 +556,7 @@ static int vb2_dma_sg_map_dmabuf(void *mem_priv) · 105 unmodified lines | |||
| 565 | } | 556 | } |
| 566 | 557 | ||
| 567 | /* get the associated scatterlist for this buffer */ | 558 | /* get the associated scatterlist for this buffer */ |
| 568 | sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); | 559 | sgt = dma_buf_map_attachment_unlocked(buf->db_attach, buf->dma_dir); |
| 569 | if (IS_ERR(sgt)) { | 560 | if (IS_ERR(sgt)) { |
| 570 | pr_err("Error getting dmabuf scatterlist\n"); | 561 | pr_err("Error getting dmabuf scatterlist\n"); |
| 571 | return -EINVAL; | 562 | return -EINVAL; |
| @@ -594,10 +585,10 @@ static void vb2_dma_sg_unmap_dmabuf(void *mem_priv) · 22 unmodified lines | |||
| 594 | } | 585 | } |
| 595 | 586 | ||
| 596 | if (buf->vaddr) { | 587 | if (buf->vaddr) { |
| 597 | dma_buf_vunmap(buf->db_attach->dmabuf, &map); | 588 | dma_buf_vunmap_unlocked(buf->db_attach->dmabuf, &map); |
| 598 | buf->vaddr = NULL; | 589 | buf->vaddr = NULL; |
| 599 | } | 590 | } |
| 600 | dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); | 591 | dma_buf_unmap_attachment_unlocked(buf->db_attach, sgt, buf->dma_dir); |
| 601 | 592 | ||
| 602 | buf->dma_sgt = NULL; | 593 | buf->dma_sgt = NULL; |
| 603 | } | 594 | } |
| @@ -267,18 +267,12 @@ static struct sg_table *vb2_vmalloc_dmabuf_ops_map( · 266 unmodified lines | |||
| 267 | struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) | 267 | struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) |
| 268 | { | 268 | { |
| 269 | struct vb2_vmalloc_attachment *attach = db_attach->priv; | 269 | struct vb2_vmalloc_attachment *attach = db_attach->priv; |
| 270 | /* stealing dmabuf mutex to serialize map/unmap operations */ | ||
| 271 | struct mutex *lock = &db_attach->dmabuf->lock; | ||
| 272 | struct sg_table *sgt; | 270 | struct sg_table *sgt; |
| 273 | 271 | ||
| 274 | mutex_lock(lock); | ||
| 275 | |||
| 276 | sgt = &attach->sgt; | 272 | sgt = &attach->sgt; |
| 277 | /* return previously mapped sg table */ | 273 | /* return previously mapped sg table */ |
| 278 | if (attach->dma_dir == dma_dir) { | 274 | if (attach->dma_dir == dma_dir) |
| 279 | mutex_unlock(lock); | ||
| 280 | return sgt; | 275 | return sgt; |
| 281 | } | ||
| 282 | 276 | ||
| 283 | /* release any previous cache */ | 277 | /* release any previous cache */ |
| 284 | if (attach->dma_dir != DMA_NONE) { | 278 | if (attach->dma_dir != DMA_NONE) { |
| @@ -289,14 +283,11 @@ static struct sg_table *vb2_vmalloc_dmabuf_ops_map( · 4 unmodified lines | |||
| 289 | /* mapping to the client with new direction */ | 283 | /* mapping to the client with new direction */ |
| 290 | if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) { | 284 | if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) { |
| 291 | pr_err("failed to map scatterlist\n"); | 285 | pr_err("failed to map scatterlist\n"); |
| 292 | mutex_unlock(lock); | ||
| 293 | return ERR_PTR(-EIO); | 286 | return ERR_PTR(-EIO); |
| 294 | } | 287 | } |
| 295 | 288 | ||
| 296 | attach->dma_dir = dma_dir; | 289 | attach->dma_dir = dma_dir; |
| 297 | 290 | ||
| 298 | mutex_unlock(lock); | ||
| 299 | |||
| 300 | return sgt; | 291 | return sgt; |
| 301 | } | 292 | } |
| 302 | 293 | ||
| @@ -376,7 +367,7 @@ static int vb2_vmalloc_map_dmabuf(void *mem_priv) · 73 unmodified lines | |||
| 376 | struct iosys_map map; | 367 | struct iosys_map map; |
| 377 | int ret; | 368 | int ret; |
| 378 | 369 | ||
| 379 | ret = dma_buf_vmap(buf->dbuf, &map); | 370 | ret = dma_buf_vmap_unlocked(buf->dbuf, &map); |
| 380 | if (ret) | 371 | if (ret) |
| 381 | return -EFAULT; | 372 | return -EFAULT; |
| 382 | buf->vaddr = map.vaddr; | 373 | buf->vaddr = map.vaddr; |
| @@ -389,7 +380,7 @@ static void vb2_vmalloc_unmap_dmabuf(void *mem_priv) · 6 unmodified lines | |||
| 389 | struct vb2_vmalloc_buf *buf = mem_priv; | 380 | struct vb2_vmalloc_buf *buf = mem_priv; |
| 390 | struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); | 381 | struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); |
| 391 | 382 | ||
| 392 | dma_buf_vunmap(buf->dbuf, &map); | 383 | dma_buf_vunmap_unlocked(buf->dbuf, &map); |
| 393 | buf->vaddr = NULL; | 384 | buf->vaddr = NULL; |
| 394 | } | 385 | } |
| 395 | 386 | ||
| @@ -399,7 +390,7 @@ static void vb2_vmalloc_detach_dmabuf(void *mem_priv) · 3 unmodified lines | |||
| 399 | struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); | 390 | struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); |
| 400 | 391 | ||
| 401 | if (buf->vaddr) | 392 | if (buf->vaddr) |
| 402 | dma_buf_vunmap(buf->dbuf, &map); | 393 | dma_buf_vunmap_unlocked(buf->dbuf, &map); |
| 403 | 394 | ||
| 404 | kfree(buf); | 395 | kfree(buf); |
| 405 | } | 396 | } |
| @@ -38,7 +38,7 @@ static void tegra_vde_release_entry(struct tegra_vde_cache_entry *entry) · 37 unmodified lines | |||
| 38 | if (entry->vde->domain) | 38 | if (entry->vde->domain) |
| 39 | tegra_vde_iommu_unmap(entry->vde, entry->iova); | 39 | tegra_vde_iommu_unmap(entry->vde, entry->iova); |
| 40 | 40 | ||
| 41 | dma_buf_unmap_attachment(entry->a, entry->sgt, entry->dma_dir); | 41 | dma_buf_unmap_attachment_unlocked(entry->a, entry->sgt, entry->dma_dir); |
| 42 | dma_buf_detach(dmabuf, entry->a); | 42 | dma_buf_detach(dmabuf, entry->a); |
| 43 | dma_buf_put(dmabuf); | 43 | dma_buf_put(dmabuf); |
| 44 | 44 | ||
| @@ -102,7 +102,7 @@ int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde, · 57 unmodified lines | |||
| 102 | goto err_unlock; | 102 | goto err_unlock; |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | sgt = dma_buf_map_attachment(attachment, dma_dir); | 105 | sgt = dma_buf_map_attachment_unlocked(attachment, dma_dir); |
| 106 | if (IS_ERR(sgt)) { | 106 | if (IS_ERR(sgt)) { |
| 107 | dev_err(dev, "Failed to get dmabufs sg_table\n"); | 107 | dev_err(dev, "Failed to get dmabufs sg_table\n"); |
| 108 | err = PTR_ERR(sgt); | 108 | err = PTR_ERR(sgt); |
| @@ -152,7 +152,7 @@ ref: · 43 unmodified lines | |||
| 152 | err_free: | 152 | err_free: |
| 153 | kfree(entry); | 153 | kfree(entry); |
| 154 | err_unmap: | 154 | err_unmap: |
| 155 | dma_buf_unmap_attachment(attachment, sgt, dma_dir); | 155 | dma_buf_unmap_attachment_unlocked(attachment, sgt, dma_dir); |
| 156 | err_detach: | 156 | err_detach: |
| 157 | dma_buf_detach(dmabuf, attachment); | 157 | dma_buf_detach(dmabuf, attachment); |
| 158 | err_unlock: | 158 | err_unlock: |
| @@ -310,8 +310,8 @@ static void fastrpc_free_map(struct kref *ref) · 309 unmodified lines | |||
| 310 | return; | 310 | return; |
| 311 | } | 311 | } |
| 312 | } | 312 | } |
| 313 | dma_buf_unmap_attachment(map->attach, map->table, | 313 | dma_buf_unmap_attachment_unlocked(map->attach, map->table, |
| 314 | DMA_BIDIRECTIONAL); | 314 | DMA_BIDIRECTIONAL); |
| 315 | dma_buf_detach(map->buf, map->attach); | 315 | dma_buf_detach(map->buf, map->attach); |
| 316 | dma_buf_put(map->buf); | 316 | dma_buf_put(map->buf); |
| 317 | } | 317 | } |
| @@ -726,7 +726,7 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, · 408 unmodified lines | |||
| 726 | goto attach_err; | 726 | goto attach_err; |
| 727 | } | 727 | } |
| 728 | 728 | ||
| 729 | map->table = dma_buf_map_attachment(map->attach, DMA_BIDIRECTIONAL); | 729 | map->table = dma_buf_map_attachment_unlocked(map->attach, DMA_BIDIRECTIONAL); |
| 730 | if (IS_ERR(map->table)) { | 730 | if (IS_ERR(map->table)) { |
| 731 | err = PTR_ERR(map->table); | 731 | err = PTR_ERR(map->table); |
| 732 | goto map_err; | 732 | goto map_err; |
| @@ -455,6 +455,7 @@ config FB_ATARI · 454 unmodified lines | |||
| 455 | config FB_OF | 455 | config FB_OF |
| 456 | bool "Open Firmware frame buffer device support" | 456 | bool "Open Firmware frame buffer device support" |
| 457 | depends on (FB = y) && PPC && (!PPC_PSERIES || PCI) | 457 | depends on (FB = y) && PPC && (!PPC_PSERIES || PCI) |
| 458 | depends on !DRM_OFDRM | ||
| 458 | select APERTURE_HELPERS | 459 | select APERTURE_HELPERS |
| 459 | select FB_CFB_FILLRECT | 460 | select FB_CFB_FILLRECT |
| 460 | select FB_CFB_COPYAREA | 461 | select FB_CFB_COPYAREA |
| @@ -600,7 +600,7 @@ dmabuf_imp_to_refs(struct gntdev_dmabuf_priv *priv, struct device *dev, · 599 unmodified lines | |||
| 600 | 600 | ||
| 601 | gntdev_dmabuf->u.imp.attach = attach; | 601 | gntdev_dmabuf->u.imp.attach = attach; |
| 602 | 602 | ||
| 603 | sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); | 603 | sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL); |
| 604 | if (IS_ERR(sgt)) { | 604 | if (IS_ERR(sgt)) { |
| 605 | ret = ERR_CAST(sgt); | 605 | ret = ERR_CAST(sgt); |
| 606 | goto fail_detach; | 606 | goto fail_detach; |
| @@ -658,7 +658,7 @@ dmabuf_imp_to_refs(struct gntdev_dmabuf_priv *priv, struct device *dev, · 51 unmodified lines | |||
| 658 | fail_end_access: | 658 | fail_end_access: |
| 659 | dmabuf_imp_end_foreign_access(gntdev_dmabuf->u.imp.refs, count); | 659 | dmabuf_imp_end_foreign_access(gntdev_dmabuf->u.imp.refs, count); |
| 660 | fail_unmap: | 660 | fail_unmap: |
| 661 | dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); | 661 | dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL); |
| 662 | fail_detach: | 662 | fail_detach: |
| 663 | dma_buf_detach(dma_buf, attach); | 663 | dma_buf_detach(dma_buf, attach); |
| 664 | fail_free_obj: | 664 | fail_free_obj: |
| @@ -708,8 +708,8 @@ static int dmabuf_imp_release(struct gntdev_dmabuf_priv *priv, u32 fd) · 43 unmodified lines | |||
| 708 | attach = gntdev_dmabuf->u.imp.attach; | 708 | attach = gntdev_dmabuf->u.imp.attach; |
| 709 | 709 | ||
| 710 | if (gntdev_dmabuf->u.imp.sgt) | 710 | if (gntdev_dmabuf->u.imp.sgt) |
| 711 | dma_buf_unmap_attachment(attach, gntdev_dmabuf->u.imp.sgt, | 711 | dma_buf_unmap_attachment_unlocked(attach, gntdev_dmabuf->u.imp.sgt, |
| 712 | DMA_BIDIRECTIONAL); | 712 | DMA_BIDIRECTIONAL); |
| 713 | dma_buf = attach->dmabuf; | 713 | dma_buf = attach->dmabuf; |
| 714 | dma_buf_detach(attach->dmabuf, attach); | 714 | dma_buf_detach(attach->dmabuf, attach); |
| 715 | dma_buf_put(dma_buf); | 715 | dma_buf_put(dma_buf); |
| @@ -58,10 +58,9 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, · 57 unmodified lines | |||
| 58 | int max_scale, | 58 | int max_scale, |
| 59 | bool can_position, | 59 | bool can_position, |
| 60 | bool can_update_disabled); | 60 | bool can_update_disabled); |
| 61 | int drm_atomic_helper_check_crtc_state(struct drm_crtc_state *crtc_state, | ||
| 62 | bool can_disable_primary_plane); | ||
| 63 | int drm_atomic_helper_check_planes(struct drm_device *dev, | 61 | int drm_atomic_helper_check_planes(struct drm_device *dev, |
| 64 | struct drm_atomic_state *state); | 62 | struct drm_atomic_state *state); |
| 63 | int drm_atomic_helper_check_crtc_primary_plane(struct drm_crtc_state *crtc_state); | ||
| 65 | int drm_atomic_helper_check(struct drm_device *dev, | 64 | int drm_atomic_helper_check(struct drm_device *dev, |
| 66 | struct drm_atomic_state *state); | 65 | struct drm_atomic_state *state); |
| 67 | void drm_atomic_helper_commit_tail(struct drm_atomic_state *state); | 66 | void drm_atomic_helper_commit_tail(struct drm_atomic_state *state); |
| @@ -70,7 +70,7 @@ void __drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_ · 69 unmodified lines | |||
| 70 | void __drm_atomic_helper_connector_reset(struct drm_connector *connector, | 70 | void __drm_atomic_helper_connector_reset(struct drm_connector *connector, |
| 71 | struct drm_connector_state *conn_state); | 71 | struct drm_connector_state *conn_state); |
| 72 | void drm_atomic_helper_connector_reset(struct drm_connector *connector); | 72 | void drm_atomic_helper_connector_reset(struct drm_connector *connector); |
| 73 | void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector); | 73 | void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector); |
| 74 | void | 74 | void |
| 75 | __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, | 75 | __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, |
| 76 | struct drm_connector_state *state); | 76 | struct drm_connector_state *state); |
| @@ -692,7 +692,8 @@ struct drm_connector_tv_margins { · 691 unmodified lines | |||
| 692 | 692 | ||
| 693 | /** | 693 | /** |
| 694 | * struct drm_tv_connector_state - TV connector related states | 694 | * struct drm_tv_connector_state - TV connector related states |
| 695 | * @subconnector: selected subconnector | 695 | * @select_subconnector: selected subconnector |
| 696 | * @subconnector: detected subconnector | ||
| 696 | * @margins: TV margins | 697 | * @margins: TV margins |
| 697 | * @mode: TV mode | 698 | * @mode: TV mode |
| 698 | * @brightness: brightness in percent | 699 | * @brightness: brightness in percent |
| @@ -703,6 +704,7 @@ struct drm_connector_tv_margins { · 4 unmodified lines | |||
| 703 | * @hue: hue in percent | 704 | * @hue: hue in percent |
| 704 | */ | 705 | */ |
| 705 | struct drm_tv_connector_state { | 706 | struct drm_tv_connector_state { |
| 707 | enum drm_mode_subconnector select_subconnector; | ||
| 706 | enum drm_mode_subconnector subconnector; | 708 | enum drm_mode_subconnector subconnector; |
| 707 | struct drm_connector_tv_margins margins; | 709 | struct drm_connector_tv_margins margins; |
| 708 | unsigned int mode; | 710 | unsigned int mode; |
| @@ -50,6 +50,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, · 49 unmodified lines | |||
| 50 | struct drm_display_mode *mode, | 50 | struct drm_display_mode *mode, |
| 51 | int x, int y, | 51 | int x, int y, |
| 52 | struct drm_framebuffer *old_fb); | 52 | struct drm_framebuffer *old_fb); |
| 53 | int drm_crtc_helper_atomic_check(struct drm_crtc *crtc, | ||
| 54 | struct drm_atomic_state *state); | ||
| 53 | bool drm_helper_crtc_in_use(struct drm_crtc *crtc); | 55 | bool drm_helper_crtc_in_use(struct drm_crtc *crtc); |
| 54 | bool drm_helper_encoder_in_use(struct drm_encoder *encoder); | 56 | bool drm_helper_encoder_in_use(struct drm_encoder *encoder); |
| 55 | 57 | ||
| @@ -97,10 +97,13 @@ struct detailed_data_string { · 96 unmodified lines | |||
| 97 | #define DRM_EDID_RANGE_OFFSET_MIN_HFREQ (1 << 2) /* 1.4 */ | 97 | #define DRM_EDID_RANGE_OFFSET_MIN_HFREQ (1 << 2) /* 1.4 */ |
| 98 | #define DRM_EDID_RANGE_OFFSET_MAX_HFREQ (1 << 3) /* 1.4 */ | 98 | #define DRM_EDID_RANGE_OFFSET_MAX_HFREQ (1 << 3) /* 1.4 */ |
| 99 | 99 | ||
| 100 | #define DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG 0x00 | 100 | #define DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG 0x00 /* 1.3 */ |
| 101 | #define DRM_EDID_RANGE_LIMITS_ONLY_FLAG 0x01 | 101 | #define DRM_EDID_RANGE_LIMITS_ONLY_FLAG 0x01 /* 1.4 */ |
| 102 | #define DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG 0x02 | 102 | #define DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG 0x02 /* 1.3 */ |
| 103 | #define DRM_EDID_CVT_SUPPORT_FLAG 0x04 | 103 | #define DRM_EDID_CVT_SUPPORT_FLAG 0x04 /* 1.4 */ |
| 104 | |||
| 105 | #define DRM_EDID_CVT_FLAGS_STANDARD_BLANKING (1 << 3) | ||
| 106 | #define DRM_EDID_CVT_FLAGS_REDUCED_BLANKING (1 << 4) | ||
| 104 | 107 | ||
| 105 | struct detailed_data_monitor_range { | 108 | struct detailed_data_monitor_range { |
| 106 | u8 min_vfreq; | 109 | u8 min_vfreq; |
| @@ -206,7 +209,8 @@ struct detailed_timing { · 99 unmodified lines | |||
| 206 | #define DRM_EDID_DIGITAL_TYPE_DP (5 << 0) /* 1.4 */ | 209 | #define DRM_EDID_DIGITAL_TYPE_DP (5 << 0) /* 1.4 */ |
| 207 | #define DRM_EDID_DIGITAL_DFP_1_X (1 << 0) /* 1.3 */ | 210 | #define DRM_EDID_DIGITAL_DFP_1_X (1 << 0) /* 1.3 */ |
| 208 | 211 | ||
| 209 | #define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 0) | 212 | #define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 0) /* 1.2 */ |
| 213 | #define DRM_EDID_FEATURE_CONTINUOUS_FREQ (1 << 0) /* 1.4 */ | ||
| 210 | #define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1) | 214 | #define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1) |
| 211 | #define DRM_EDID_FEATURE_STANDARD_COLOR (1 << 2) | 215 | #define DRM_EDID_FEATURE_STANDARD_COLOR (1 << 2) |
| 212 | /* If analog */ | 216 | /* If analog */ |
| @@ -457,6 +457,9 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj); · 456 unmodified lines | |||
| 457 | void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, | 457 | void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, |
| 458 | bool dirty, bool accessed); | 458 | bool dirty, bool accessed); |
| 459 | 459 | ||
| 460 | int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map); | ||
| 461 | void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map); | ||
| 462 | |||
| 460 | int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, | 463 | int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, |
| 461 | int count, struct drm_gem_object ***objs_out); | 464 | int count, struct drm_gem_object ***objs_out); |
| 462 | struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); | 465 | struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); |
| @@ -345,7 +345,6 @@ struct drm_mode_config_funcs { · 344 unmodified lines | |||
| 345 | * @max_width: maximum fb pixel width on this device | 345 | * @max_width: maximum fb pixel width on this device |
| 346 | * @max_height: maximum fb pixel height on this device | 346 | * @max_height: maximum fb pixel height on this device |
| 347 | * @funcs: core driver provided mode setting functions | 347 | * @funcs: core driver provided mode setting functions |
| 348 | * @fb_base: base address of the framebuffer | ||
| 349 | * @poll_enabled: track polling support for this device | 348 | * @poll_enabled: track polling support for this device |
| 350 | * @poll_running: track polling status for this device | 349 | * @poll_running: track polling status for this device |
| 351 | * @delayed_event: track delayed poll uevent deliver for this device | 350 | * @delayed_event: track delayed poll uevent deliver for this device |
| @@ -542,7 +541,6 @@ struct drm_mode_config { · 190 unmodified lines | |||
| 542 | int min_width, min_height; | 541 | int min_width, min_height; |
| 543 | int max_width, max_height; | 542 | int max_width, max_height; |
| 544 | const struct drm_mode_config_funcs *funcs; | 543 | const struct drm_mode_config_funcs *funcs; |
| 545 | resource_size_t fb_base; | ||
| 546 | 544 | ||
| 547 | /* output poll support */ | 545 | /* output poll support */ |
| 548 | bool poll_enabled; | 546 | bool poll_enabled; |
| @@ -59,6 +59,12 @@ enum drm_sched_priority { · 58 unmodified lines | |||
| 59 | DRM_SCHED_PRIORITY_UNSET = -2 | 59 | DRM_SCHED_PRIORITY_UNSET = -2 |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | /* Used to chose between FIFO and RR jobs scheduling */ | ||
| 63 | extern int drm_sched_policy; | ||
| 64 | |||
| 65 | #define DRM_SCHED_POLICY_RR 0 | ||
| 66 | #define DRM_SCHED_POLICY_FIFO 1 | ||
| 67 | |||
| 62 | /** | 68 | /** |
| 63 | * struct drm_sched_entity - A wrapper around a job queue (typically | 69 | * struct drm_sched_entity - A wrapper around a job queue (typically |
| 64 | * attached to the DRM file_priv). | 70 | * attached to the DRM file_priv). |
| @@ -205,6 +211,21 @@ struct drm_sched_entity { · 140 unmodified lines | |||
| 205 | * drm_sched_entity_fini(). | 211 | * drm_sched_entity_fini(). |
| 206 | */ | 212 | */ |
| 207 | struct completion entity_idle; | 213 | struct completion entity_idle; |
| 214 | |||
| 215 | /** | ||
| 216 | * @oldest_job_waiting: | ||
| 217 | * | ||
| 218 | * Marks earliest job waiting in SW queue | ||
| 219 | */ | ||
| 220 | ktime_t oldest_job_waiting; | ||
| 221 | |||
| 222 | /** | ||
| 223 | * @rb_tree_node: | ||
| 224 | * | ||
| 225 | * The node used to insert this entity into time based priority queue | ||
| 226 | */ | ||
| 227 | struct rb_node rb_tree_node; | ||
| 228 | |||
| 208 | }; | 229 | }; |
| 209 | 230 | ||
| 210 | /** | 231 | /** |
| @@ -214,6 +235,7 @@ struct drm_sched_entity { · 3 unmodified lines | |||
| 214 | * @sched: the scheduler to which this rq belongs to. | 235 | * @sched: the scheduler to which this rq belongs to. |
| 215 | * @entities: list of the entities to be scheduled. | 236 | * @entities: list of the entities to be scheduled. |
| 216 | * @current_entity: the entity which is to be scheduled. | 237 | * @current_entity: the entity which is to be scheduled. |
| 238 | * @rb_tree_root: root of time based priory queue of entities for FIFO scheduling | ||
| 217 | * | 239 | * |
| 218 | * Run queue is a set of entities scheduling command submissions for | 240 | * Run queue is a set of entities scheduling command submissions for |
| 219 | * one specific ring. It implements the scheduling policy that selects | 241 | * one specific ring. It implements the scheduling policy that selects |
| @@ -224,6 +246,7 @@ struct drm_sched_rq { · 4 unmodified lines | |||
| 224 | struct drm_gpu_scheduler *sched; | 246 | struct drm_gpu_scheduler *sched; |
| 225 | struct list_head entities; | 247 | struct list_head entities; |
| 226 | struct drm_sched_entity *current_entity; | 248 | struct drm_sched_entity *current_entity; |
| 249 | struct rb_root_cached rb_tree_root; | ||
| 227 | }; | 250 | }; |
| 228 | 251 | ||
| 229 | /** | 252 | /** |
| @@ -323,6 +346,13 @@ struct drm_sched_job { · 93 unmodified lines | |||
| 323 | 346 | ||
| 324 | /** @last_dependency: tracks @dependencies as they signal */ | 347 | /** @last_dependency: tracks @dependencies as they signal */ |
| 325 | unsigned long last_dependency; | 348 | unsigned long last_dependency; |
| 349 | |||
| 350 | /** | ||
| 351 | * @submit_ts: | ||
| 352 | * | ||
| 353 | * When the job was pushed into the entity queue. | ||
| 354 | */ | ||
| 355 | ktime_t submit_ts; | ||
| 326 | }; | 356 | }; |
| 327 | 357 | ||
| 328 | static inline bool drm_sched_invalidate_job(struct drm_sched_job *s_job, | 358 | static inline bool drm_sched_invalidate_job(struct drm_sched_job *s_job, |
| @@ -512,6 +542,8 @@ void drm_sched_rq_add_entity(struct drm_sched_rq *rq, · 183 unmodified lines | |||
| 512 | void drm_sched_rq_remove_entity(struct drm_sched_rq *rq, | 542 | void drm_sched_rq_remove_entity(struct drm_sched_rq *rq, |
| 513 | struct drm_sched_entity *entity); | 543 | struct drm_sched_entity *entity); |
| 514 | 544 | ||
| 545 | void drm_sched_rq_update_fifo(struct drm_sched_entity *entity, ktime_t ts); | ||
| 546 | |||
| 515 | int drm_sched_entity_init(struct drm_sched_entity *entity, | 547 | int drm_sched_entity_init(struct drm_sched_entity *entity, |
| 516 | enum drm_sched_priority priority, | 548 | enum drm_sched_priority priority, |
| 517 | struct drm_gpu_scheduler **sched_list, | 549 | struct drm_gpu_scheduler **sched_list, |
| @@ -326,15 +326,6 @@ struct dma_buf { · 325 unmodified lines | |||
| 326 | /** @ops: dma_buf_ops associated with this buffer object. */ | 326 | /** @ops: dma_buf_ops associated with this buffer object. */ |
| 327 | const struct dma_buf_ops *ops; | 327 | const struct dma_buf_ops *ops; |
| 328 | 328 | ||
| 329 | /** | ||
| 330 | * @lock: | ||
| 331 | * | ||
| 332 | * Used internally to serialize list manipulation, attach/detach and | ||
| 333 | * vmap/unmap. Note that in many cases this is superseeded by | ||
| 334 | * dma_resv_lock() on @resv. | ||
| 335 | */ | ||
| 336 | struct mutex lock; | ||
| 337 | |||
| 338 | /** | 329 | /** |
| 339 | * @vmapping_counter: | 330 | * @vmapping_counter: |
| 340 | * | 331 | * |
| @@ -627,9 +618,17 @@ int dma_buf_begin_cpu_access(struct dma_buf *dma_buf, · 286 unmodified lines | |||
| 627 | enum dma_data_direction dir); | 618 | enum dma_data_direction dir); |
| 628 | int dma_buf_end_cpu_access(struct dma_buf *dma_buf, | 619 | int dma_buf_end_cpu_access(struct dma_buf *dma_buf, |
| 629 | enum dma_data_direction dir); | 620 | enum dma_data_direction dir); |
| 621 | struct sg_table * | ||
| 622 | dma_buf_map_attachment_unlocked(struct dma_buf_attachment *attach, | ||
| 623 | enum dma_data_direction direction); | ||
| 624 | void dma_buf_unmap_attachment_unlocked(struct dma_buf_attachment *attach, | ||
| 625 | struct sg_table *sg_table, | ||
| 626 | enum dma_data_direction direction); | ||
| 630 | 627 | ||
| 631 | int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, | 628 | int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, |
| 632 | unsigned long); | 629 | unsigned long); |
| 633 | int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map); | 630 | int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map); |
| 634 | void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map); | 631 | void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map); |
| 632 | int dma_buf_vmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map); | ||
| 633 | void dma_buf_vunmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map); | ||
| 635 | #endif /* __DMA_BUF_H__ */ | 634 | #endif /* __DMA_BUF_H__ */ |
| @@ -744,6 +744,35 @@ extern "C" { · 743 unmodified lines | |||
| 744 | */ | 744 | */ |
| 745 | #define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4) | 745 | #define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4) |
| 746 | 746 | ||
| 747 | /* | ||
| 748 | * Vivante TS (tile-status) buffer modifiers. They can be combined with all of | ||
| 749 | * the color buffer tiling modifiers defined above. When TS is present it's a | ||
| 750 | * separate buffer containing the clear/compression status of each tile. The | ||
| 751 | * modifiers are defined as VIVANTE_MOD_TS_c_s, where c is the color buffer | ||
| 752 | * tile size in bytes covered by one entry in the status buffer and s is the | ||
| 753 | * number of status bits per entry. | ||
| 754 | * We reserve the top 8 bits of the Vivante modifier space for tile status | ||
| 755 | * clear/compression modifiers, as future cores might add some more TS layout | ||
| 756 | * variations. | ||
| 757 | */ | ||
| 758 | #define VIVANTE_MOD_TS_64_4 (1ULL << 48) | ||
| 759 | #define VIVANTE_MOD_TS_64_2 (2ULL << 48) | ||
| 760 | #define VIVANTE_MOD_TS_128_4 (3ULL << 48) | ||
| 761 | #define VIVANTE_MOD_TS_256_4 (4ULL << 48) | ||
| 762 | #define VIVANTE_MOD_TS_MASK (0xfULL << 48) | ||
| 763 | |||
| 764 | /* | ||
| 765 | * Vivante compression modifiers. Those depend on a TS modifier being present | ||
| 766 | * as the TS bits get reinterpreted as compression tags instead of simple | ||
| 767 | * clear markers when compression is enabled. | ||
| 768 | */ | ||
| 769 | #define VIVANTE_MOD_COMP_DEC400 (1ULL << 52) | ||
| 770 | #define VIVANTE_MOD_COMP_MASK (0xfULL << 52) | ||
| 771 | |||
| 772 | /* Masking out the extension bits will yield the base modifier. */ | ||
| 773 | #define VIVANTE_MOD_EXT_MASK (VIVANTE_MOD_TS_MASK | \ | ||
| 774 | VIVANTE_MOD_COMP_MASK) | ||
| 775 | |||
| 747 | /* NVIDIA frame buffer modifiers */ | 776 | /* NVIDIA frame buffer modifiers */ |
| 748 | 777 | ||
| 749 | /* | 778 | /* |
| @@ -935,12 +935,31 @@ struct hdr_output_metadata { · 934 unmodified lines | |||
| 935 | }; | 935 | }; |
| 936 | }; | 936 | }; |
| 937 | 937 | ||
| 938 | /** | ||
| 939 | * DRM_MODE_PAGE_FLIP_EVENT | ||
| 940 | * | ||
| 941 | * Request that the kernel sends back a vblank event (see | ||
| 942 | * struct drm_event_vblank) with the &DRM_EVENT_FLIP_COMPLETE type when the | ||
| 943 | * page-flip is done. | ||
| 944 | */ | ||
| 938 | #define DRM_MODE_PAGE_FLIP_EVENT 0x01 | 945 | #define DRM_MODE_PAGE_FLIP_EVENT 0x01 |
| 946 | /** | ||
| 947 | * DRM_MODE_PAGE_FLIP_ASYNC | ||
| 948 | * | ||
| 949 | * Request that the page-flip is performed as soon as possible, ie. with no | ||
| 950 | * delay due to waiting for vblank. This may cause tearing to be visible on | ||
| 951 | * the screen. | ||
| 952 | */ | ||
| 939 | #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 | 953 | #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 |
| 940 | #define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 | 954 | #define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 |
| 941 | #define DRM_MODE_PAGE_FLIP_TARGET_RELATIVE 0x8 | 955 | #define DRM_MODE_PAGE_FLIP_TARGET_RELATIVE 0x8 |
| 942 | #define DRM_MODE_PAGE_FLIP_TARGET (DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | \ | 956 | #define DRM_MODE_PAGE_FLIP_TARGET (DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | \ |
| 943 | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE) | 957 | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE) |
| 958 | /** | ||
| 959 | * DRM_MODE_PAGE_FLIP_FLAGS | ||
| 960 | * | ||
| 961 | * Bitmask of flags suitable for &drm_mode_crtc_page_flip_target.flags. | ||
| 962 | */ | ||
| 944 | #define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT | \ | 963 | #define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT | \ |
| 945 | DRM_MODE_PAGE_FLIP_ASYNC | \ | 964 | DRM_MODE_PAGE_FLIP_ASYNC | \ |
| 946 | DRM_MODE_PAGE_FLIP_TARGET) | 965 | DRM_MODE_PAGE_FLIP_TARGET) |
| @@ -1034,11 +1053,53 @@ struct drm_mode_destroy_dumb { · 87 unmodified lines | |||
| 1034 | __u32 handle; | 1053 | __u32 handle; |
| 1035 | }; | 1054 | }; |
| 1036 | 1055 | ||
| 1037 | /* page-flip flags are valid, plus: */ | 1056 | /** |
| 1057 | * DRM_MODE_ATOMIC_TEST_ONLY | ||
| 1058 | * | ||
| 1059 | * Do not apply the atomic commit, instead check whether the hardware supports | ||
| 1060 | * this configuration. | ||
| 1061 | * | ||
| 1062 | * See &drm_mode_config_funcs.atomic_check for more details on test-only | ||
| 1063 | * commits. | ||
| 1064 | */ | ||
| 1038 | #define DRM_MODE_ATOMIC_TEST_ONLY 0x0100 | 1065 | #define DRM_MODE_ATOMIC_TEST_ONLY 0x0100 |
| 1066 | /** | ||
| 1067 | * DRM_MODE_ATOMIC_NONBLOCK | ||
| 1068 | * | ||
| 1069 | * Do not block while applying the atomic commit. The &DRM_IOCTL_MODE_ATOMIC | ||
| 1070 | * IOCTL returns immediately instead of waiting for the changes to be applied | ||
| 1071 | * in hardware. Note, the driver will still check that the update can be | ||
| 1072 | * applied before retuning. | ||
| 1073 | */ | ||
| 1039 | #define DRM_MODE_ATOMIC_NONBLOCK 0x0200 | 1074 | #define DRM_MODE_ATOMIC_NONBLOCK 0x0200 |
| 1075 | /** | ||
| 1076 | * DRM_MODE_ATOMIC_ALLOW_MODESET | ||
| 1077 | * | ||
| 1078 | * Allow the update to result in temporary or transient visible artifacts while | ||
| 1079 | * the update is being applied. Applying the update may also take significantly | ||
| 1080 | * more time than a page flip. All visual artifacts will disappear by the time | ||
| 1081 | * the update is completed, as signalled through the vblank event's timestamp | ||
| 1082 | * (see struct drm_event_vblank). | ||
| 1083 | * | ||
| 1084 | * This flag must be set when the KMS update might cause visible artifacts. | ||
| 1085 | * Without this flag such KMS update will return a EINVAL error. What kind of | ||
| 1086 | * update may cause visible artifacts depends on the driver and the hardware. | ||
| 1087 | * User-space that needs to know beforehand if an update might cause visible | ||
| 1088 | * artifacts can use &DRM_MODE_ATOMIC_TEST_ONLY without | ||
| 1089 | * &DRM_MODE_ATOMIC_ALLOW_MODESET to see if it fails. | ||
| 1090 | * | ||
| 1091 | * To the best of the driver's knowledge, visual artifacts are guaranteed to | ||
| 1092 | * not appear when this flag is not set. Some sinks might display visual | ||
| 1093 | * artifacts outside of the driver's control. | ||
| 1094 | */ | ||
| 1040 | #define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400 | 1095 | #define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400 |
| 1041 | 1096 | ||
| 1097 | /** | ||
| 1098 | * DRM_MODE_ATOMIC_FLAGS | ||
| 1099 | * | ||
| 1100 | * Bitfield of flags accepted by the &DRM_IOCTL_MODE_ATOMIC IOCTL in | ||
| 1101 | * &drm_mode_atomic.flags. | ||
| 1102 | */ | ||
| 1042 | #define DRM_MODE_ATOMIC_FLAGS (\ | 1103 | #define DRM_MODE_ATOMIC_FLAGS (\ |
| 1043 | DRM_MODE_PAGE_FLIP_EVENT |\ | 1104 | DRM_MODE_PAGE_FLIP_EVENT |\ |
| 1044 | DRM_MODE_PAGE_FLIP_ASYNC |\ | 1105 | DRM_MODE_PAGE_FLIP_ASYNC |\ |