diff options
author | Bartosz Golaszewski <bgolaszewski@baylibre.com> | 2016-10-31 10:19:26 -0400 |
---|---|---|
committer | Jyri Sarha <jsarha@ti.com> | 2016-11-30 07:18:36 -0500 |
commit | 9345235e9c67c216af000631ba898c21e5a3f30d (patch) | |
tree | 0b76d253ab3beaa7b4d67ab149623c0924463e9c | |
parent | cba8844a687e444f8af694f453de501c6e92e54d (diff) |
drm/tilcdc: implement palette loading for rev1
Revision 1 of the IP doesn't work if we don't load the palette (even
if it's not used, which is the case for the RGB565 format).
Add a function called from tilcdc_crtc_enable() which performs all
required actions if we're dealing with a rev1 chip.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: Jyri Sarha <jsarha@ti.com>
Tested-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 88 |
1 files changed, 87 insertions, 1 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 01692409f613..7ea34c21c384 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c | |||
@@ -21,11 +21,15 @@ | |||
21 | #include <drm/drm_flip_work.h> | 21 | #include <drm/drm_flip_work.h> |
22 | #include <drm/drm_plane_helper.h> | 22 | #include <drm/drm_plane_helper.h> |
23 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
24 | #include <linux/completion.h> | ||
25 | #include <linux/dma-mapping.h> | ||
24 | 26 | ||
25 | #include "tilcdc_drv.h" | 27 | #include "tilcdc_drv.h" |
26 | #include "tilcdc_regs.h" | 28 | #include "tilcdc_regs.h" |
27 | 29 | ||
28 | #define TILCDC_VBLANK_SAFETY_THRESHOLD_US 1000 | 30 | #define TILCDC_VBLANK_SAFETY_THRESHOLD_US 1000 |
31 | #define TILCDC_REV1_PALETTE_SIZE 32 | ||
32 | #define TILCDC_REV1_PALETTE_FIRST_ENTRY 0x4000 | ||
29 | 33 | ||
30 | struct tilcdc_crtc { | 34 | struct tilcdc_crtc { |
31 | struct drm_crtc base; | 35 | struct drm_crtc base; |
@@ -56,6 +60,10 @@ struct tilcdc_crtc { | |||
56 | int sync_lost_count; | 60 | int sync_lost_count; |
57 | bool frame_intact; | 61 | bool frame_intact; |
58 | struct work_struct recover_work; | 62 | struct work_struct recover_work; |
63 | |||
64 | dma_addr_t palette_dma_handle; | ||
65 | void *palette_base; | ||
66 | struct completion palette_loaded; | ||
59 | }; | 67 | }; |
60 | #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) | 68 | #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) |
61 | 69 | ||
@@ -105,6 +113,55 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) | |||
105 | tilcdc_crtc->curr_fb = fb; | 113 | tilcdc_crtc->curr_fb = fb; |
106 | } | 114 | } |
107 | 115 | ||
116 | /* | ||
117 | * The driver currently only supports the RGB565 format for revision 1. For | ||
118 | * 16 bits-per-pixel the palette block is bypassed, but the first 32 bytes of | ||
119 | * the framebuffer are still considered palette. The first 16-bit entry must | ||
120 | * be 0x4000 while all other entries must be zeroed. | ||
121 | */ | ||
122 | static void tilcdc_crtc_load_palette(struct drm_crtc *crtc) | ||
123 | { | ||
124 | u32 dma_fb_base, dma_fb_ceiling, raster_ctl; | ||
125 | struct tilcdc_crtc *tilcdc_crtc; | ||
126 | struct drm_device *dev; | ||
127 | u16 *first_entry; | ||
128 | |||
129 | dev = crtc->dev; | ||
130 | tilcdc_crtc = to_tilcdc_crtc(crtc); | ||
131 | first_entry = tilcdc_crtc->palette_base; | ||
132 | |||
133 | *first_entry = TILCDC_REV1_PALETTE_FIRST_ENTRY; | ||
134 | |||
135 | dma_fb_base = tilcdc_read(dev, LCDC_DMA_FB_BASE_ADDR_0_REG); | ||
136 | dma_fb_ceiling = tilcdc_read(dev, LCDC_DMA_FB_CEILING_ADDR_0_REG); | ||
137 | raster_ctl = tilcdc_read(dev, LCDC_RASTER_CTRL_REG); | ||
138 | |||
139 | /* Tell the LCDC where the palette is located. */ | ||
140 | tilcdc_write(dev, LCDC_DMA_FB_BASE_ADDR_0_REG, | ||
141 | tilcdc_crtc->palette_dma_handle); | ||
142 | tilcdc_write(dev, LCDC_DMA_FB_CEILING_ADDR_0_REG, | ||
143 | (u32)tilcdc_crtc->palette_dma_handle | ||
144 | + TILCDC_REV1_PALETTE_SIZE - 1); | ||
145 | |||
146 | /* Load it. */ | ||
147 | tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, | ||
148 | LCDC_PALETTE_LOAD_MODE(DATA_ONLY)); | ||
149 | tilcdc_set(dev, LCDC_RASTER_CTRL_REG, | ||
150 | LCDC_PALETTE_LOAD_MODE(PALETTE_ONLY)); | ||
151 | |||
152 | /* Enable the LCDC and wait for palette to be loaded. */ | ||
153 | tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_V1_PL_INT_ENA); | ||
154 | tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); | ||
155 | |||
156 | wait_for_completion(&tilcdc_crtc->palette_loaded); | ||
157 | |||
158 | /* Restore the registers. */ | ||
159 | tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); | ||
160 | tilcdc_write(dev, LCDC_DMA_FB_BASE_ADDR_0_REG, dma_fb_base); | ||
161 | tilcdc_write(dev, LCDC_DMA_FB_CEILING_ADDR_0_REG, dma_fb_ceiling); | ||
162 | tilcdc_write(dev, LCDC_RASTER_CTRL_REG, raster_ctl); | ||
163 | } | ||
164 | |||
108 | static void tilcdc_crtc_enable_irqs(struct drm_device *dev) | 165 | static void tilcdc_crtc_enable_irqs(struct drm_device *dev) |
109 | { | 166 | { |
110 | struct tilcdc_drm_private *priv = dev->dev_private; | 167 | struct tilcdc_drm_private *priv = dev->dev_private; |
@@ -161,6 +218,7 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc) | |||
161 | { | 218 | { |
162 | struct drm_device *dev = crtc->dev; | 219 | struct drm_device *dev = crtc->dev; |
163 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 220 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
221 | struct tilcdc_drm_private *priv = dev->dev_private; | ||
164 | 222 | ||
165 | WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); | 223 | WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); |
166 | mutex_lock(&tilcdc_crtc->enable_lock); | 224 | mutex_lock(&tilcdc_crtc->enable_lock); |
@@ -173,6 +231,9 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc) | |||
173 | 231 | ||
174 | reset(crtc); | 232 | reset(crtc); |
175 | 233 | ||
234 | if (priv->rev == 1 && !completion_done(&tilcdc_crtc->palette_loaded)) | ||
235 | tilcdc_crtc_load_palette(crtc); | ||
236 | |||
176 | tilcdc_crtc_enable_irqs(dev); | 237 | tilcdc_crtc_enable_irqs(dev); |
177 | 238 | ||
178 | tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_DUAL_FRAME_BUFFER_ENABLE); | 239 | tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_DUAL_FRAME_BUFFER_ENABLE); |
@@ -214,6 +275,13 @@ static void tilcdc_crtc_off(struct drm_crtc *crtc, bool shutdown) | |||
214 | __func__); | 275 | __func__); |
215 | } | 276 | } |
216 | 277 | ||
278 | /* | ||
279 | * LCDC will not retain the palette when reset. Make sure it gets | ||
280 | * reloaded on tilcdc_crtc_enable(). | ||
281 | */ | ||
282 | if (priv->rev == 1) | ||
283 | reinit_completion(&tilcdc_crtc->palette_loaded); | ||
284 | |||
217 | drm_crtc_vblank_off(crtc); | 285 | drm_crtc_vblank_off(crtc); |
218 | 286 | ||
219 | tilcdc_crtc_disable_irqs(dev); | 287 | tilcdc_crtc_disable_irqs(dev); |
@@ -847,6 +915,14 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc) | |||
847 | dev_err_ratelimited(dev->dev, "%s(0x%08x): FIFO underflow", | 915 | dev_err_ratelimited(dev->dev, "%s(0x%08x): FIFO underflow", |
848 | __func__, stat); | 916 | __func__, stat); |
849 | 917 | ||
918 | if (priv->rev == 1) { | ||
919 | if (stat & LCDC_PL_LOAD_DONE) { | ||
920 | complete(&tilcdc_crtc->palette_loaded); | ||
921 | tilcdc_clear(dev, | ||
922 | LCDC_RASTER_CTRL_REG, LCDC_V1_PL_INT_ENA); | ||
923 | } | ||
924 | } | ||
925 | |||
850 | if (stat & LCDC_SYNC_LOST) { | 926 | if (stat & LCDC_SYNC_LOST) { |
851 | dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost", | 927 | dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost", |
852 | __func__, stat); | 928 | __func__, stat); |
@@ -894,6 +970,16 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev) | |||
894 | return NULL; | 970 | return NULL; |
895 | } | 971 | } |
896 | 972 | ||
973 | if (priv->rev == 1) { | ||
974 | init_completion(&tilcdc_crtc->palette_loaded); | ||
975 | tilcdc_crtc->palette_base = dmam_alloc_coherent(dev->dev, | ||
976 | TILCDC_REV1_PALETTE_SIZE, | ||
977 | &tilcdc_crtc->palette_dma_handle, | ||
978 | GFP_KERNEL | __GFP_ZERO); | ||
979 | if (!tilcdc_crtc->palette_base) | ||
980 | return ERR_PTR(-ENOMEM); | ||
981 | } | ||
982 | |||
897 | crtc = &tilcdc_crtc->base; | 983 | crtc = &tilcdc_crtc->base; |
898 | 984 | ||
899 | ret = tilcdc_plane_init(dev, &tilcdc_crtc->primary); | 985 | ret = tilcdc_plane_init(dev, &tilcdc_crtc->primary); |