Merge remote-tracking branches 'asoc/topic/cs35l35', 'asoc/topic/cs53l30', 'asoc...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / mxsfb / mxsfb_crtc.c
1 /*
2  * Copyright (C) 2016 Marek Vasut <marex@denx.de>
3  *
4  * This code is based on drivers/video/fbdev/mxsfb.c :
5  * Copyright (C) 2010 Juergen Beisert, Pengutronix
6  * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
7  * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18
19 #include <drm/drmP.h>
20 #include <drm/drm_atomic_helper.h>
21 #include <drm/drm_crtc.h>
22 #include <drm/drm_crtc_helper.h>
23 #include <drm/drm_fb_helper.h>
24 #include <drm/drm_fb_cma_helper.h>
25 #include <drm/drm_gem_cma_helper.h>
26 #include <drm/drm_of.h>
27 #include <drm/drm_plane_helper.h>
28 #include <drm/drm_simple_kms_helper.h>
29 #include <linux/clk.h>
30 #include <linux/iopoll.h>
31 #include <linux/of_graph.h>
32 #include <linux/platform_data/simplefb.h>
33 #include <video/videomode.h>
34
35 #include "mxsfb_drv.h"
36 #include "mxsfb_regs.h"
37
38 static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
39 {
40         return (val & mxsfb->devdata->hs_wdth_mask) <<
41                 mxsfb->devdata->hs_wdth_shift;
42 }
43
44 /* Setup the MXSFB registers for decoding the pixels out of the framebuffer */
45 static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb)
46 {
47         struct drm_crtc *crtc = &mxsfb->pipe.crtc;
48         struct drm_device *drm = crtc->dev;
49         const u32 format = crtc->primary->state->fb->format->format;
50         u32 ctrl, ctrl1;
51
52         ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
53
54         /*
55          * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to
56          * match the selected mode here. This differs from the original
57          * MXSFB driver, which had the option to configure the bus width
58          * to arbitrary value. This limitation should not pose an issue.
59          */
60
61         /* CTRL1 contains IRQ config and status bits, preserve those. */
62         ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
63         ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
64
65         switch (format) {
66         case DRM_FORMAT_RGB565:
67                 dev_dbg(drm->dev, "Setting up RGB565 mode\n");
68                 ctrl |= CTRL_SET_WORD_LENGTH(0);
69                 ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
70                 break;
71         case DRM_FORMAT_XRGB8888:
72                 dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
73                 ctrl |= CTRL_SET_WORD_LENGTH(3);
74                 /* Do not use packed pixels = one pixel per word instead. */
75                 ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
76                 break;
77         default:
78                 dev_err(drm->dev, "Unhandled pixel format %08x\n", format);
79                 return -EINVAL;
80         }
81
82         writel(ctrl1, mxsfb->base + LCDC_CTRL1);
83         writel(ctrl, mxsfb->base + LCDC_CTRL);
84
85         return 0;
86 }
87
88 static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
89 {
90         struct drm_crtc *crtc = &mxsfb->pipe.crtc;
91         struct drm_device *drm = crtc->dev;
92         u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
93         u32 reg;
94
95         reg = readl(mxsfb->base + LCDC_CTRL);
96
97         if (mxsfb->connector.display_info.num_bus_formats)
98                 bus_format = mxsfb->connector.display_info.bus_formats[0];
99
100         reg &= ~CTRL_BUS_WIDTH_MASK;
101         switch (bus_format) {
102         case MEDIA_BUS_FMT_RGB565_1X16:
103                 reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
104                 break;
105         case MEDIA_BUS_FMT_RGB666_1X18:
106                 reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
107                 break;
108         case MEDIA_BUS_FMT_RGB888_1X24:
109                 reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
110                 break;
111         default:
112                 dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
113                 break;
114         }
115         writel(reg, mxsfb->base + LCDC_CTRL);
116 }
117
118 static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
119 {
120         u32 reg;
121
122         if (mxsfb->clk_disp_axi)
123                 clk_prepare_enable(mxsfb->clk_disp_axi);
124         clk_prepare_enable(mxsfb->clk);
125         mxsfb_enable_axi_clk(mxsfb);
126
127         /* If it was disabled, re-enable the mode again */
128         writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
129
130         /* Enable the SYNC signals first, then the DMA engine */
131         reg = readl(mxsfb->base + LCDC_VDCTRL4);
132         reg |= VDCTRL4_SYNC_SIGNALS_ON;
133         writel(reg, mxsfb->base + LCDC_VDCTRL4);
134
135         writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
136 }
137
138 static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
139 {
140         u32 reg;
141
142         /*
143          * Even if we disable the controller here, it will still continue
144          * until its FIFOs are running out of data
145          */
146         writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
147
148         readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
149                            0, 1000);
150
151         reg = readl(mxsfb->base + LCDC_VDCTRL4);
152         reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
153         writel(reg, mxsfb->base + LCDC_VDCTRL4);
154
155         mxsfb_disable_axi_clk(mxsfb);
156
157         clk_disable_unprepare(mxsfb->clk);
158         if (mxsfb->clk_disp_axi)
159                 clk_disable_unprepare(mxsfb->clk_disp_axi);
160 }
161
162 static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
163 {
164         struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
165         const u32 bus_flags = mxsfb->connector.display_info.bus_flags;
166         u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
167         int err;
168
169         /*
170          * It seems, you can't re-program the controller if it is still
171          * running. This may lead to shifted pictures (FIFO issue?), so
172          * first stop the controller and drain its FIFOs.
173          */
174         mxsfb_enable_axi_clk(mxsfb);
175
176         /* Clear the FIFOs */
177         writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
178
179         err = mxsfb_set_pixel_fmt(mxsfb);
180         if (err)
181                 return;
182
183         clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
184
185         writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
186                TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
187                mxsfb->base + mxsfb->devdata->transfer_count);
188
189         vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
190
191         vdctrl0 = VDCTRL0_ENABLE_PRESENT |      /* Always in DOTCLOCK mode */
192                   VDCTRL0_VSYNC_PERIOD_UNIT |
193                   VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
194                   VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
195         if (m->flags & DRM_MODE_FLAG_PHSYNC)
196                 vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
197         if (m->flags & DRM_MODE_FLAG_PVSYNC)
198                 vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
199         /* Make sure Data Enable is high active by default */
200         if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
201                 vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
202         /*
203          * DRM_BUS_FLAG_PIXDATA_ defines are controller centric,
204          * controllers VDCTRL0_DOTCLK is display centric.
205          * Drive on positive edge       -> display samples on falling edge
206          * DRM_BUS_FLAG_PIXDATA_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
207          */
208         if (bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
209                 vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
210
211         writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
212
213         mxsfb_set_bus_fmt(mxsfb);
214
215         /* Frame length in lines. */
216         writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
217
218         /* Line length in units of clocks or pixels. */
219         hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
220         writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
221                VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
222                mxsfb->base + LCDC_VDCTRL2);
223
224         writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
225                SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
226                mxsfb->base + LCDC_VDCTRL3);
227
228         writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
229                mxsfb->base + LCDC_VDCTRL4);
230
231         mxsfb_disable_axi_clk(mxsfb);
232 }
233
234 void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
235 {
236         mxsfb_crtc_mode_set_nofb(mxsfb);
237         mxsfb_enable_controller(mxsfb);
238 }
239
240 void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
241 {
242         mxsfb_disable_controller(mxsfb);
243 }
244
245 void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
246                                struct drm_plane_state *state)
247 {
248         struct drm_simple_display_pipe *pipe = &mxsfb->pipe;
249         struct drm_crtc *crtc = &pipe->crtc;
250         struct drm_framebuffer *fb = pipe->plane.state->fb;
251         struct drm_pending_vblank_event *event;
252         struct drm_gem_cma_object *gem;
253
254         if (!crtc)
255                 return;
256
257         spin_lock_irq(&crtc->dev->event_lock);
258         event = crtc->state->event;
259         if (event) {
260                 crtc->state->event = NULL;
261
262                 if (drm_crtc_vblank_get(crtc) == 0) {
263                         drm_crtc_arm_vblank_event(crtc, event);
264                 } else {
265                         drm_crtc_send_vblank_event(crtc, event);
266                 }
267         }
268         spin_unlock_irq(&crtc->dev->event_lock);
269
270         if (!fb)
271                 return;
272
273         gem = drm_fb_cma_get_gem_obj(fb, 0);
274
275         mxsfb_enable_axi_clk(mxsfb);
276         writel(gem->paddr, mxsfb->base + mxsfb->devdata->next_buf);
277         mxsfb_disable_axi_clk(mxsfb);
278 }