1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Allwinner DW HDMI bridge
4  *
5  * (C) Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net>
6  */
7 
8 #include <common.h>
9 #include <display.h>
10 #include <dm.h>
11 #include <dw_hdmi.h>
12 #include <edid.h>
13 #include <log.h>
14 #include <time.h>
15 #include <asm/io.h>
16 #include <asm/arch/clock.h>
17 #include <asm/arch/lcdc.h>
18 #include <linux/bitops.h>
19 #include <linux/delay.h>
20 
21 struct sunxi_dw_hdmi_priv {
22 	struct dw_hdmi hdmi;
23 };
24 
25 struct sunxi_hdmi_phy {
26 	u32 pol;
27 	u32 res1[3];
28 	u32 read_en;
29 	u32 unscramble;
30 	u32 res2[2];
31 	u32 ctrl;
32 	u32 unk1;
33 	u32 unk2;
34 	u32 pll;
35 	u32 clk;
36 	u32 unk3;
37 	u32 status;
38 };
39 
40 #define HDMI_PHY_OFFS 0x10000
41 
sunxi_dw_hdmi_get_divider(uint clock)42 static int sunxi_dw_hdmi_get_divider(uint clock)
43 {
44 	/*
45 	 * Due to missing documentaion of HDMI PHY, we know correct
46 	 * settings only for following four PHY dividers. Select one
47 	 * based on clock speed.
48 	 */
49 	if (clock <= 27000000)
50 		return 11;
51 	else if (clock <= 74250000)
52 		return 4;
53 	else if (clock <= 148500000)
54 		return 2;
55 	else
56 		return 1;
57 }
58 
sunxi_dw_hdmi_phy_init(void)59 static void sunxi_dw_hdmi_phy_init(void)
60 {
61 	struct sunxi_hdmi_phy * const phy =
62 		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
63 	unsigned long tmo;
64 	u32 tmp;
65 
66 	/*
67 	 * HDMI PHY settings are taken as-is from Allwinner BSP code.
68 	 * There is no documentation.
69 	 */
70 	writel(0, &phy->ctrl);
71 	setbits_le32(&phy->ctrl, BIT(0));
72 	udelay(5);
73 	setbits_le32(&phy->ctrl, BIT(16));
74 	setbits_le32(&phy->ctrl, BIT(1));
75 	udelay(10);
76 	setbits_le32(&phy->ctrl, BIT(2));
77 	udelay(5);
78 	setbits_le32(&phy->ctrl, BIT(3));
79 	udelay(40);
80 	setbits_le32(&phy->ctrl, BIT(19));
81 	udelay(100);
82 	setbits_le32(&phy->ctrl, BIT(18));
83 	setbits_le32(&phy->ctrl, 7 << 4);
84 
85 	/* Note that Allwinner code doesn't fail in case of timeout */
86 	tmo = timer_get_us() + 2000;
87 	while ((readl(&phy->status) & 0x80) == 0) {
88 		if (timer_get_us() > tmo) {
89 			printf("Warning: HDMI PHY init timeout!\n");
90 			break;
91 		}
92 	}
93 
94 	setbits_le32(&phy->ctrl, 0xf << 8);
95 	setbits_le32(&phy->ctrl, BIT(7));
96 
97 	writel(0x39dc5040, &phy->pll);
98 	writel(0x80084343, &phy->clk);
99 	udelay(10000);
100 	writel(1, &phy->unk3);
101 	setbits_le32(&phy->pll, BIT(25));
102 	udelay(100000);
103 	tmp = (readl(&phy->status) & 0x1f800) >> 11;
104 	setbits_le32(&phy->pll, BIT(31) | BIT(30));
105 	setbits_le32(&phy->pll, tmp);
106 	writel(0x01FF0F7F, &phy->ctrl);
107 	writel(0x80639000, &phy->unk1);
108 	writel(0x0F81C405, &phy->unk2);
109 
110 	/* enable read access to HDMI controller */
111 	writel(0x54524545, &phy->read_en);
112 	/* descramble register offsets */
113 	writel(0x42494E47, &phy->unscramble);
114 }
115 
sunxi_dw_hdmi_phy_set(uint clock,int phy_div)116 static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div)
117 {
118 	struct sunxi_hdmi_phy * const phy =
119 		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
120 	int div = sunxi_dw_hdmi_get_divider(clock);
121 	u32 tmp;
122 
123 	/*
124 	 * Unfortunately, we don't know much about those magic
125 	 * numbers. They are taken from Allwinner BSP driver.
126 	 */
127 	switch (div) {
128 	case 1:
129 		writel(0x30dc5fc0, &phy->pll);
130 		writel(0x800863C0 | (phy_div - 1), &phy->clk);
131 		mdelay(10);
132 		writel(0x00000001, &phy->unk3);
133 		setbits_le32(&phy->pll, BIT(25));
134 		mdelay(200);
135 		tmp = (readl(&phy->status) & 0x1f800) >> 11;
136 		setbits_le32(&phy->pll, BIT(31) | BIT(30));
137 		if (tmp < 0x3d)
138 			setbits_le32(&phy->pll, tmp + 2);
139 		else
140 			setbits_le32(&phy->pll, 0x3f);
141 		mdelay(100);
142 		writel(0x01FFFF7F, &phy->ctrl);
143 		writel(0x8063b000, &phy->unk1);
144 		writel(0x0F8246B5, &phy->unk2);
145 		break;
146 	case 2:
147 		writel(0x39dc5040, &phy->pll);
148 		writel(0x80084380 | (phy_div - 1), &phy->clk);
149 		mdelay(10);
150 		writel(0x00000001, &phy->unk3);
151 		setbits_le32(&phy->pll, BIT(25));
152 		mdelay(100);
153 		tmp = (readl(&phy->status) & 0x1f800) >> 11;
154 		setbits_le32(&phy->pll, BIT(31) | BIT(30));
155 		setbits_le32(&phy->pll, tmp);
156 		writel(0x01FFFF7F, &phy->ctrl);
157 		writel(0x8063a800, &phy->unk1);
158 		writel(0x0F81C485, &phy->unk2);
159 		break;
160 	case 4:
161 		writel(0x39dc5040, &phy->pll);
162 		writel(0x80084340 | (phy_div - 1), &phy->clk);
163 		mdelay(10);
164 		writel(0x00000001, &phy->unk3);
165 		setbits_le32(&phy->pll, BIT(25));
166 		mdelay(100);
167 		tmp = (readl(&phy->status) & 0x1f800) >> 11;
168 		setbits_le32(&phy->pll, BIT(31) | BIT(30));
169 		setbits_le32(&phy->pll, tmp);
170 		writel(0x01FFFF7F, &phy->ctrl);
171 		writel(0x8063b000, &phy->unk1);
172 		writel(0x0F81C405, &phy->unk2);
173 		break;
174 	case 11:
175 		writel(0x39dc5040, &phy->pll);
176 		writel(0x80084300 | (phy_div - 1), &phy->clk);
177 		mdelay(10);
178 		writel(0x00000001, &phy->unk3);
179 		setbits_le32(&phy->pll, BIT(25));
180 		mdelay(100);
181 		tmp = (readl(&phy->status) & 0x1f800) >> 11;
182 		setbits_le32(&phy->pll, BIT(31) | BIT(30));
183 		setbits_le32(&phy->pll, tmp);
184 		writel(0x01FFFF7F, &phy->ctrl);
185 		writel(0x8063b000, &phy->unk1);
186 		writel(0x0F81C405, &phy->unk2);
187 		break;
188 	}
189 }
190 
sunxi_dw_hdmi_pll_set(uint clk_khz,int * phy_div)191 static void sunxi_dw_hdmi_pll_set(uint clk_khz, int *phy_div)
192 {
193 	int value, n, m, div, diff;
194 	int best_n = 0, best_m = 0, best_div = 0, best_diff = 0x0FFFFFFF;
195 
196 	/*
197 	 * Find the lowest divider resulting in a matching clock. If there
198 	 * is no match, pick the closest lower clock, as monitors tend to
199 	 * not sync to higher frequencies.
200 	 */
201 	for (div = 1; div <= 16; div++) {
202 		int target = clk_khz * div;
203 
204 		if (target < 192000)
205 			continue;
206 		if (target > 912000)
207 			continue;
208 
209 		for (m = 1; m <= 16; m++) {
210 			n = (m * target) / 24000;
211 
212 			if (n >= 1 && n <= 128) {
213 				value = (24000 * n) / m / div;
214 				diff = clk_khz - value;
215 				if (diff < best_diff) {
216 					best_diff = diff;
217 					best_m = m;
218 					best_n = n;
219 					best_div = div;
220 				}
221 			}
222 		}
223 	}
224 
225 	*phy_div = best_div;
226 
227 	clock_set_pll3_factors(best_m, best_n);
228 	debug("dotclock: %dkHz = %dkHz: (24MHz * %d) / %d / %d\n",
229 	      clk_khz, (clock_get_pll3() / 1000) / best_div,
230 	      best_n, best_m, best_div);
231 }
232 
sunxi_dw_hdmi_lcdc_init(int mux,const struct display_timing * edid,int bpp)233 static void sunxi_dw_hdmi_lcdc_init(int mux, const struct display_timing *edid,
234 				    int bpp)
235 {
236 	struct sunxi_ccm_reg * const ccm =
237 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
238 	int div = DIV_ROUND_UP(clock_get_pll3(), edid->pixelclock.typ);
239 	struct sunxi_lcdc_reg *lcdc;
240 
241 	if (mux == 0) {
242 		lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
243 
244 		/* Reset off */
245 		setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
246 
247 		/* Clock on */
248 		setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
249 		writel(CCM_LCD0_CTRL_GATE | CCM_LCD0_CTRL_M(div),
250 		       &ccm->lcd0_clk_cfg);
251 	} else {
252 		lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD1_BASE;
253 
254 		/* Reset off */
255 		setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD1);
256 
257 		/* Clock on */
258 		setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD1);
259 		writel(CCM_LCD1_CTRL_GATE | CCM_LCD1_CTRL_M(div),
260 		       &ccm->lcd1_clk_cfg);
261 	}
262 
263 	lcdc_init(lcdc);
264 	lcdc_tcon1_mode_set(lcdc, edid, false, false);
265 	lcdc_enable(lcdc, bpp);
266 }
267 
sunxi_dw_hdmi_phy_cfg(struct dw_hdmi * hdmi,uint mpixelclock)268 static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock)
269 {
270 	int phy_div;
271 
272 	sunxi_dw_hdmi_pll_set(mpixelclock / 1000, &phy_div);
273 	sunxi_dw_hdmi_phy_set(mpixelclock, phy_div);
274 
275 	return 0;
276 }
277 
sunxi_dw_hdmi_read_edid(struct udevice * dev,u8 * buf,int buf_size)278 static int sunxi_dw_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size)
279 {
280 	struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
281 
282 	return dw_hdmi_read_edid(&priv->hdmi, buf, buf_size);
283 }
284 
sunxi_dw_hdmi_mode_valid(struct udevice * dev,const struct display_timing * timing)285 static bool sunxi_dw_hdmi_mode_valid(struct udevice *dev,
286 				     const struct display_timing *timing)
287 {
288 	return timing->pixelclock.typ <= 297000000;
289 }
290 
sunxi_dw_hdmi_enable(struct udevice * dev,int panel_bpp,const struct display_timing * edid)291 static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
292 				const struct display_timing *edid)
293 {
294 	struct sunxi_hdmi_phy * const phy =
295 		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
296 	struct display_plat *uc_plat = dev_get_uclass_plat(dev);
297 	struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
298 	int ret;
299 
300 	ret = dw_hdmi_enable(&priv->hdmi, edid);
301 	if (ret)
302 		return ret;
303 
304 	sunxi_dw_hdmi_lcdc_init(uc_plat->source_id, edid, panel_bpp);
305 
306 	if (edid->flags & DISPLAY_FLAGS_VSYNC_LOW)
307 		setbits_le32(&phy->pol, 0x200);
308 
309 	if (edid->flags & DISPLAY_FLAGS_HSYNC_LOW)
310 		setbits_le32(&phy->pol, 0x100);
311 
312 	setbits_le32(&phy->ctrl, 0xf << 12);
313 
314 	/*
315 	 * This is last hdmi access before boot, so scramble addresses
316 	 * again or othwerwise BSP driver won't work. Dummy read is
317 	 * needed or otherwise last write doesn't get written correctly.
318 	 */
319 	(void)readb(SUNXI_HDMI_BASE);
320 	writel(0, &phy->unscramble);
321 
322 	return 0;
323 }
324 
sunxi_dw_hdmi_probe(struct udevice * dev)325 static int sunxi_dw_hdmi_probe(struct udevice *dev)
326 {
327 	struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
328 	struct sunxi_ccm_reg * const ccm =
329 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
330 	int ret;
331 
332 	/* Set pll3 to 297 MHz */
333 	clock_set_pll3(297000000);
334 
335 	/* Set hdmi parent to pll3 */
336 	clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
337 			CCM_HDMI_CTRL_PLL3);
338 
339 	/* Set ahb gating to pass */
340 	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
341 	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI2);
342 	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
343 	setbits_le32(&ccm->hdmi_slow_clk_cfg, CCM_HDMI_SLOW_CTRL_DDC_GATE);
344 
345 	/* Clock on */
346 	setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
347 
348 	sunxi_dw_hdmi_phy_init();
349 
350 	priv->hdmi.ioaddr = SUNXI_HDMI_BASE;
351 	priv->hdmi.i2c_clk_high = 0xd8;
352 	priv->hdmi.i2c_clk_low = 0xfe;
353 	priv->hdmi.reg_io_width = 1;
354 	priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg;
355 
356 	ret = dw_hdmi_phy_wait_for_hpd(&priv->hdmi);
357 	if (ret < 0) {
358 		debug("hdmi can not get hpd signal\n");
359 		return -1;
360 	}
361 
362 	dw_hdmi_init(&priv->hdmi);
363 
364 	return 0;
365 }
366 
367 static const struct dm_display_ops sunxi_dw_hdmi_ops = {
368 	.read_edid = sunxi_dw_hdmi_read_edid,
369 	.enable = sunxi_dw_hdmi_enable,
370 	.mode_valid = sunxi_dw_hdmi_mode_valid,
371 };
372 
373 U_BOOT_DRIVER(sunxi_dw_hdmi) = {
374 	.name	= "sunxi_dw_hdmi",
375 	.id	= UCLASS_DISPLAY,
376 	.ops	= &sunxi_dw_hdmi_ops,
377 	.probe	= sunxi_dw_hdmi_probe,
378 	.priv_auto	= sizeof(struct sunxi_dw_hdmi_priv),
379 };
380 
381 U_BOOT_DRVINFO(sunxi_dw_hdmi) = {
382 	.name = "sunxi_dw_hdmi"
383 };
384