blob: 5fa6f794eccef7c182a829e71ae39b299c906cb2 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Hannes Petermaierf04e9992014-03-06 14:39:06 +01002/*
Hannes Schmelzer2d9a3cd2018-01-09 19:01:32 +01003 * Copyright (C) 2013-2018 Hannes Schmelzer <oe5hpm@oevsv.at>
4 * B&R Industrial Automation GmbH - http://www.br-automation.com
Dario Binacchi017b4692020-02-22 14:05:45 +01005 * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
Hannes Petermaierf04e9992014-03-06 14:39:06 +01006 *
7 * minimal framebuffer driver for TI's AM335x SoC to be compatible with
8 * Wolfgang Denk's LCD-Framework (CONFIG_LCD, common/lcd.c)
9 *
Martin Pietryka8664c222016-04-27 21:39:15 +020010 * - supporting 16/24/32bit RGB/TFT raster Mode (not using palette)
Hannes Petermaierf04e9992014-03-06 14:39:06 +010011 * - sets up LCD controller as in 'am335x_lcdpanel' struct given
12 * - starts output DMA from gd->fb_base buffer
Hannes Petermaierf04e9992014-03-06 14:39:06 +010013 */
14#include <common.h>
Dario Binacchi763e7362020-05-03 21:27:48 +020015#include <lcd.h>
Simon Glass0f2af882020-05-10 11:40:05 -060016#include <log.h>
Dario Binacchi763e7362020-05-03 21:27:48 +020017#include <asm/arch/clock.h>
Hannes Petermaierf04e9992014-03-06 14:39:06 +010018#include <asm/arch/hardware.h>
Hannes Schmelzer6e1e4282018-01-09 19:01:34 +010019#include <asm/arch/omap.h>
Hannes Schmelzer6e1e4282018-01-09 19:01:34 +010020#include <asm/arch/sys_proto.h>
Dario Binacchi763e7362020-05-03 21:27:48 +020021#include <asm/io.h>
Simon Glassdbd79542020-05-10 11:40:11 -060022#include <linux/delay.h>
Dario Binacchi5a4ed092020-02-22 14:05:44 +010023#include <linux/err.h>
Hannes Petermaierf04e9992014-03-06 14:39:06 +010024#include "am335x-fb.h"
25
Hannes Schmelzer6e1e4282018-01-09 19:01:34 +010026#define LCDC_FMAX 200000000
Hannes Petermaierf04e9992014-03-06 14:39:06 +010027
28/* LCD Control Register */
Dario Binacchi5a4ed092020-02-22 14:05:44 +010029#define LCDC_CTRL_CLK_DIVISOR_MASK GENMASK(15, 8)
Dario Binacchi33dfa792020-02-22 14:05:41 +010030#define LCDC_CTRL_RASTER_MODE BIT(0)
31#define LCDC_CTRL_CLK_DIVISOR(x) (((x) & GENMASK(7, 0)) << 8)
Hannes Petermaierf04e9992014-03-06 14:39:06 +010032/* LCD Clock Enable Register */
Dario Binacchi33dfa792020-02-22 14:05:41 +010033#define LCDC_CLKC_ENABLE_CORECLKEN BIT(0)
34#define LCDC_CLKC_ENABLE_LIDDCLKEN BIT(1)
35#define LCDC_CLKC_ENABLE_DMACLKEN BIT(2)
Hannes Petermaierf04e9992014-03-06 14:39:06 +010036/* LCD DMA Control Register */
Dario Binacchi33dfa792020-02-22 14:05:41 +010037#define LCDC_DMA_CTRL_BURST_SIZE(x) (((x) & GENMASK(2, 0)) << 4)
38#define LCDC_DMA_CTRL_BURST_1 0x0
39#define LCDC_DMA_CTRL_BURST_2 0x1
40#define LCDC_DMA_CTRL_BURST_4 0x2
41#define LCDC_DMA_CTRL_BURST_8 0x3
42#define LCDC_DMA_CTRL_BURST_16 0x4
Dario Binacchi017b4692020-02-22 14:05:45 +010043#define LCDC_DMA_CTRL_FIFO_TH(x) (((x) & GENMASK(2, 0)) << 8)
Hannes Petermaierf04e9992014-03-06 14:39:06 +010044/* LCD Timing_0 Register */
Dario Binacchibd0b9692020-02-22 14:05:48 +010045#define LCDC_RASTER_TIMING_0_HORMSB(x) ((((x) - 1) & BIT(10)) >> 7)
Dario Binacchi33dfa792020-02-22 14:05:41 +010046#define LCDC_RASTER_TIMING_0_HORLSB(x) (((((x) >> 4) - 1) & GENMASK(5, 0)) << 4)
47#define LCDC_RASTER_TIMING_0_HSWLSB(x) ((((x) - 1) & GENMASK(5, 0)) << 10)
48#define LCDC_RASTER_TIMING_0_HFPLSB(x) ((((x) - 1) & GENMASK(7, 0)) << 16)
49#define LCDC_RASTER_TIMING_0_HBPLSB(x) ((((x) - 1) & GENMASK(7, 0)) << 24)
Hannes Petermaierf04e9992014-03-06 14:39:06 +010050/* LCD Timing_1 Register */
Dario Binacchi33dfa792020-02-22 14:05:41 +010051#define LCDC_RASTER_TIMING_1_VERLSB(x) (((x) - 1) & GENMASK(9, 0))
52#define LCDC_RASTER_TIMING_1_VSW(x) ((((x) - 1) & GENMASK(5, 0)) << 10)
53#define LCDC_RASTER_TIMING_1_VFP(x) (((x) & GENMASK(7, 0)) << 16)
54#define LCDC_RASTER_TIMING_1_VBP(x) (((x) & GENMASK(7, 0)) << 24)
Hannes Petermaierf04e9992014-03-06 14:39:06 +010055/* LCD Timing_2 Register */
Dario Binacchi33dfa792020-02-22 14:05:41 +010056#define LCDC_RASTER_TIMING_2_HFPMSB(x) ((((x) - 1) & GENMASK(9, 8)) >> 8)
57#define LCDC_RASTER_TIMING_2_HBPMSB(x) ((((x) - 1) & GENMASK(9, 8)) >> 4)
Dario Binacchi017b4692020-02-22 14:05:45 +010058#define LCDC_RASTER_TIMING_2_ACB(x) (((x) & GENMASK(7, 0)) << 8)
59#define LCDC_RASTER_TIMING_2_ACBI(x) (((x) & GENMASK(3, 0)) << 16)
60#define LCDC_RASTER_TIMING_2_VSYNC_INVERT BIT(20)
61#define LCDC_RASTER_TIMING_2_HSYNC_INVERT BIT(21)
62#define LCDC_RASTER_TIMING_2_PXCLK_INVERT BIT(22)
63#define LCDC_RASTER_TIMING_2_DE_INVERT BIT(23)
64#define LCDC_RASTER_TIMING_2_HSVS_RISEFALL BIT(24)
65#define LCDC_RASTER_TIMING_2_HSVS_CONTROL BIT(25)
Dario Binacchi33dfa792020-02-22 14:05:41 +010066#define LCDC_RASTER_TIMING_2_VERMSB(x) ((((x) - 1) & BIT(10)) << 16)
67#define LCDC_RASTER_TIMING_2_HSWMSB(x) ((((x) - 1) & GENMASK(9, 6)) << 21)
Hannes Petermaierf04e9992014-03-06 14:39:06 +010068/* LCD Raster Ctrl Register */
Dario Binacchi33dfa792020-02-22 14:05:41 +010069#define LCDC_RASTER_CTRL_ENABLE BIT(0)
70#define LCDC_RASTER_CTRL_TFT_MODE BIT(7)
Dario Binacchi017b4692020-02-22 14:05:45 +010071#define LCDC_RASTER_CTRL_DATA_ORDER BIT(8)
72#define LCDC_RASTER_CTRL_REQDLY(x) (((x) & GENMASK(7, 0)) << 12)
Dario Binacchi33dfa792020-02-22 14:05:41 +010073#define LCDC_RASTER_CTRL_PALMODE_RAWDATA (0x02 << 20)
Dario Binacchi017b4692020-02-22 14:05:45 +010074#define LCDC_RASTER_CTRL_TFT_ALT_ENABLE BIT(23)
Dario Binacchi33dfa792020-02-22 14:05:41 +010075#define LCDC_RASTER_CTRL_TFT_24BPP_MODE BIT(25)
76#define LCDC_RASTER_CTRL_TFT_24BPP_UNPACK BIT(26)
Hannes Petermaierf04e9992014-03-06 14:39:06 +010077
Hannes Petermaierf04e9992014-03-06 14:39:06 +010078struct am335x_lcdhw {
79 unsigned int pid; /* 0x00 */
80 unsigned int ctrl; /* 0x04 */
81 unsigned int gap0; /* 0x08 */
82 unsigned int lidd_ctrl; /* 0x0C */
83 unsigned int lidd_cs0_conf; /* 0x10 */
84 unsigned int lidd_cs0_addr; /* 0x14 */
85 unsigned int lidd_cs0_data; /* 0x18 */
86 unsigned int lidd_cs1_conf; /* 0x1C */
87 unsigned int lidd_cs1_addr; /* 0x20 */
88 unsigned int lidd_cs1_data; /* 0x24 */
89 unsigned int raster_ctrl; /* 0x28 */
90 unsigned int raster_timing0; /* 0x2C */
91 unsigned int raster_timing1; /* 0x30 */
92 unsigned int raster_timing2; /* 0x34 */
93 unsigned int raster_subpanel; /* 0x38 */
94 unsigned int raster_subpanel2; /* 0x3C */
95 unsigned int lcddma_ctrl; /* 0x40 */
96 unsigned int lcddma_fb0_base; /* 0x44 */
97 unsigned int lcddma_fb0_ceiling; /* 0x48 */
98 unsigned int lcddma_fb1_base; /* 0x4C */
99 unsigned int lcddma_fb1_ceiling; /* 0x50 */
100 unsigned int sysconfig; /* 0x54 */
101 unsigned int irqstatus_raw; /* 0x58 */
102 unsigned int irqstatus; /* 0x5C */
103 unsigned int irqenable_set; /* 0x60 */
104 unsigned int irqenable_clear; /* 0x64 */
105 unsigned int gap1; /* 0x68 */
106 unsigned int clkc_enable; /* 0x6C */
107 unsigned int clkc_reset; /* 0x70 */
108};
109
Dario Binacchi0dc48192020-12-30 00:16:29 +0100110DECLARE_GLOBAL_DATA_PTR;
111
Dario Binacchi0dc48192020-12-30 00:16:29 +0100112#if !defined(LCD_CNTL_BASE)
113#error "hw-base address of LCD-Controller (LCD_CNTL_BASE) not defined!"
114#endif
115
116/* Macro definitions */
117#define FBSIZE(x) (((x)->hactive * (x)->vactive * (x)->bpp) >> 3)
118
119#define LCDC_RASTER_TIMING_2_INVMASK(x) ((x) & GENMASK(25, 20))
120
121static struct am335x_lcdhw *lcdhw = (void *)LCD_CNTL_BASE;
122
123int lcd_get_size(int *line_length)
124{
125 *line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
126 return *line_length * panel_info.vl_row + 0x20;
127}
128
Dario Binacchi5a4ed092020-02-22 14:05:44 +0100129struct dpll_data {
130 unsigned long rounded_rate;
131 u16 rounded_m;
132 u8 rounded_n;
133 u8 rounded_div;
134};
135
Dario Binacchi5a4ed092020-02-22 14:05:44 +0100136/**
137 * am335x_dpll_round_rate() - Round a target rate for an OMAP DPLL
138 *
139 * @dpll_data: struct dpll_data pointer for the DPLL
140 * @rate: New DPLL clock rate
141 * @return rounded rate and the computed m, n and div values in the dpll_data
142 * structure, or -ve error code.
143 */
144static ulong am335x_dpll_round_rate(struct dpll_data *dd, ulong rate)
145{
146 unsigned int m, n, d;
147 unsigned long rounded_rate;
148 int err, err_r;
149
150 dd->rounded_rate = -EFAULT;
151 err = rate;
152 err_r = err;
153
154 for (d = 2; err && d < 255; d++) {
155 for (m = 2; m < 2047; m++) {
156 if ((V_OSCK * m) < (rate * d))
157 continue;
158
159 n = (V_OSCK * m) / (rate * d);
160 if (n > 127)
161 break;
162
163 if (((V_OSCK * m) / n) > LCDC_FMAX)
164 break;
165
166 rounded_rate = (V_OSCK * m) / n / d;
167 err = abs(rounded_rate - rate);
168 if (err < err_r) {
169 err_r = err;
170 dd->rounded_rate = rounded_rate;
171 dd->rounded_m = m;
172 dd->rounded_n = n;
173 dd->rounded_div = d;
174 if (err == 0)
175 break;
176 }
177 }
178 }
179
180 debug("DPLL display: best error %d Hz (M %d, N %d, DIV %d)\n",
181 err_r, dd->rounded_m, dd->rounded_n, dd->rounded_div);
182
183 return dd->rounded_rate;
184}
185
186/**
187 * am335x_fb_set_pixel_clk_rate() - Set pixel clock rate.
188 *
189 * @am335x_lcdhw: Base address of the LCD controller registers.
190 * @rate: New clock rate in Hz.
191 * @return new rate, or -ve error code.
192 */
193static ulong am335x_fb_set_pixel_clk_rate(struct am335x_lcdhw *regs, ulong rate)
194{
195 struct dpll_params dpll_disp = { 1, 0, 1, -1, -1, -1, -1 };
196 struct dpll_data dd;
197 ulong round_rate;
198 u32 reg;
199
200 round_rate = am335x_dpll_round_rate(&dd, rate);
201 if (IS_ERR_VALUE(round_rate))
202 return round_rate;
203
204 dpll_disp.m = dd.rounded_m;
205 dpll_disp.n = dd.rounded_n;
206 do_setup_dpll(&dpll_disp_regs, &dpll_disp);
207
208 reg = readl(&regs->ctrl) & ~LCDC_CTRL_CLK_DIVISOR_MASK;
209 reg |= LCDC_CTRL_CLK_DIVISOR(dd.rounded_div);
210 writel(reg, &regs->ctrl);
211 return round_rate;
212}
213
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100214int am335xfb_init(struct am335x_lcdpanel *panel)
215{
Martin Pietryka8664c222016-04-27 21:39:15 +0200216 u32 raster_ctrl = 0;
Hannes Schmelzer6e1e4282018-01-09 19:01:34 +0100217 struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
Dario Binacchi5a4ed092020-02-22 14:05:44 +0100218 ulong rate;
219 u32 reg;
Hannes Schmelzer6e1e4282018-01-09 19:01:34 +0100220
Hannes Schmelzera301aa42018-01-09 19:01:33 +0100221 if (gd->fb_base == 0) {
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100222 printf("ERROR: no valid fb_base stored in GLOBAL_DATA_PTR!\n");
223 return -1;
224 }
Hannes Schmelzera301aa42018-01-09 19:01:33 +0100225 if (panel == NULL) {
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100226 printf("ERROR: missing ptr to am335x_lcdpanel!\n");
227 return -1;
228 }
229
Martin Pietryka8664c222016-04-27 21:39:15 +0200230 /* We can already set the bits for the raster_ctrl in this check */
231 switch (panel->bpp) {
232 case 16:
233 break;
234 case 32:
Dario Binacchi33dfa792020-02-22 14:05:41 +0100235 raster_ctrl |= LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
Martin Pietryka8664c222016-04-27 21:39:15 +0200236 /* fallthrough */
237 case 24:
Dario Binacchi33dfa792020-02-22 14:05:41 +0100238 raster_ctrl |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
Martin Pietryka8664c222016-04-27 21:39:15 +0200239 break;
240 default:
Masahiro Yamada81e10422017-09-16 14:10:41 +0900241 pr_err("am335x-fb: invalid bpp value: %d\n", panel->bpp);
Martin Pietryka8664c222016-04-27 21:39:15 +0200242 return -1;
243 }
244
Hannes Schmelzer6e1e4282018-01-09 19:01:34 +0100245 /* check given clock-frequency */
246 if (panel->pxl_clk > (LCDC_FMAX / 2)) {
247 pr_err("am335x-fb: requested pxl-clk: %d not supported!\n",
248 panel->pxl_clk);
249 return -1;
250 }
251
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100252 debug("setting up LCD-Controller for %dx%dx%d (hfp=%d,hbp=%d,hsw=%d / ",
253 panel->hactive, panel->vactive, panel->bpp,
254 panel->hfp, panel->hbp, panel->hsw);
Hannes Schmelzer6e1e4282018-01-09 19:01:34 +0100255 debug("vfp=%d,vbp=%d,vsw=%d / clk=%d)\n",
256 panel->vfp, panel->vfp, panel->vsw, panel->pxl_clk);
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100257 debug("using frambuffer at 0x%08x with size %d.\n",
258 (unsigned int)gd->fb_base, FBSIZE(panel));
259
Dario Binacchi5a4ed092020-02-22 14:05:44 +0100260 rate = am335x_fb_set_pixel_clk_rate(lcdhw, panel->pxl_clk);
261 if (IS_ERR_VALUE(rate))
262 return rate;
Hannes Schmelzer6e1e4282018-01-09 19:01:34 +0100263
264 /* clock source for LCDC from dispPLL M2 */
265 writel(0x0, &cmdpll->clklcdcpixelclk);
266
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100267 /* palette default entry */
268 memset((void *)gd->fb_base, 0, 0x20);
269 *(unsigned int *)gd->fb_base = 0x4000;
Martin Pietryka3707a682016-04-27 21:39:16 +0200270 /* point fb behind palette */
271 gd->fb_base += 0x20;
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100272
Hannes Petermaier169aa702015-02-03 13:22:23 +0100273 /* turn ON display through powercontrol function if accessible */
Hannes Schmelzera301aa42018-01-09 19:01:33 +0100274 if (panel->panel_power_ctrl != NULL)
Hannes Petermaier169aa702015-02-03 13:22:23 +0100275 panel->panel_power_ctrl(1);
276
277 debug("am335x-fb: wait for stable power ...\n");
278 mdelay(panel->pup_delay);
Dario Binacchi33dfa792020-02-22 14:05:41 +0100279 lcdhw->clkc_enable = LCDC_CLKC_ENABLE_CORECLKEN |
280 LCDC_CLKC_ENABLE_LIDDCLKEN | LCDC_CLKC_ENABLE_DMACLKEN;
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100281 lcdhw->raster_ctrl = 0;
Dario Binacchi5a4ed092020-02-22 14:05:44 +0100282
283 reg = lcdhw->ctrl & LCDC_CTRL_CLK_DIVISOR_MASK;
284 reg |= LCDC_CTRL_RASTER_MODE;
285 lcdhw->ctrl = reg;
286
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100287 lcdhw->lcddma_fb0_base = gd->fb_base;
Martin Pietryka3707a682016-04-27 21:39:16 +0200288 lcdhw->lcddma_fb0_ceiling = gd->fb_base + FBSIZE(panel);
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100289 lcdhw->lcddma_fb1_base = gd->fb_base;
Martin Pietryka3707a682016-04-27 21:39:16 +0200290 lcdhw->lcddma_fb1_ceiling = gd->fb_base + FBSIZE(panel);
Dario Binacchi33dfa792020-02-22 14:05:41 +0100291 lcdhw->lcddma_ctrl = LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_16);
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100292
Dario Binacchi33dfa792020-02-22 14:05:41 +0100293 lcdhw->raster_timing0 = LCDC_RASTER_TIMING_0_HORLSB(panel->hactive) |
294 LCDC_RASTER_TIMING_0_HORMSB(panel->hactive) |
295 LCDC_RASTER_TIMING_0_HFPLSB(panel->hfp) |
296 LCDC_RASTER_TIMING_0_HBPLSB(panel->hbp) |
297 LCDC_RASTER_TIMING_0_HSWLSB(panel->hsw);
298 lcdhw->raster_timing1 = LCDC_RASTER_TIMING_1_VBP(panel->vbp) |
299 LCDC_RASTER_TIMING_1_VFP(panel->vfp) |
300 LCDC_RASTER_TIMING_1_VSW(panel->vsw) |
301 LCDC_RASTER_TIMING_1_VERLSB(panel->vactive);
302 lcdhw->raster_timing2 = LCDC_RASTER_TIMING_2_HSWMSB(panel->hsw) |
303 LCDC_RASTER_TIMING_2_VERMSB(panel->vactive) |
304 LCDC_RASTER_TIMING_2_INVMASK(panel->pol) |
305 LCDC_RASTER_TIMING_2_HBPMSB(panel->hbp) |
306 LCDC_RASTER_TIMING_2_HFPMSB(panel->hfp) |
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100307 0x0000FF00; /* clk cycles for ac-bias */
Martin Pietryka8664c222016-04-27 21:39:15 +0200308 lcdhw->raster_ctrl = raster_ctrl |
Dario Binacchi33dfa792020-02-22 14:05:41 +0100309 LCDC_RASTER_CTRL_PALMODE_RAWDATA |
310 LCDC_RASTER_CTRL_TFT_MODE |
311 LCDC_RASTER_CTRL_ENABLE;
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100312
Hannes Petermaier169aa702015-02-03 13:22:23 +0100313 debug("am335x-fb: waiting picture to be stable.\n.");
314 mdelay(panel->pon_delay);
Hannes Petermaierf04e9992014-03-06 14:39:06 +0100315
Dario Binacchi017b4692020-02-22 14:05:45 +0100316 return 0;
317}