1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 *  arch/arm/mach-rpc/include/mach/acornfb.h
4 *
5 *  Copyright (C) 1999 Russell King
6 *
7 *  AcornFB architecture specific code
8 */
9
10#define acornfb_bandwidth(var) ((var)->pixclock * 8 / (var)->bits_per_pixel)
11
12static inline int
13acornfb_valid_pixrate(struct fb_var_screeninfo *var)
14{
15	u_long limit;
16
17	if (!var->pixclock)
18		return 0;
19
20	/*
21	 * Limits below are taken from RISC OS bandwidthlimit file
22	 */
23	if (current_par.using_vram) {
24		if (current_par.vram_half_sam == 2048)
25			limit = 6578;
26		else
27			limit = 13157;
28	} else {
29		limit = 26315;
30	}
31
32	return acornfb_bandwidth(var) >= limit;
33}
34
35/*
36 * Try to find the best PLL parameters for the pixel clock.
37 * This algorithm seems to give best predictable results,
38 * and produces the same values as detailed in the VIDC20
39 * data sheet.
40 */
41static inline u_int
42acornfb_vidc20_find_pll(u_int pixclk)
43{
44	u_int r, best_r = 2, best_v = 2;
45	int best_d = 0x7fffffff;
46
47	for (r = 2; r <= 32; r++) {
48		u_int rr, v, p;
49		int d;
50
51		rr = 41667 * r;
52
53		v = (rr + pixclk / 2) / pixclk;
54
55		if (v > 32 || v < 2)
56			continue;
57
58		p = (rr + v / 2) / v;
59
60		d = pixclk - p;
61
62		if (d < 0)
63			d = -d;
64
65		if (d < best_d) {
66			best_d = d;
67			best_v = v - 1;
68			best_r = r - 1;
69		}
70
71		if (d == 0)
72			break;
73	}
74
75	return best_v << 8 | best_r;
76}
77
78static inline void
79acornfb_vidc20_find_rates(struct vidc_timing *vidc,
80			  struct fb_var_screeninfo *var)
81{
82	u_int div;
83
84	/* Select pixel-clock divisor to keep PLL in range */
85	div = var->pixclock / 9090; /*9921*/
86
87	/* Limit divisor */
88	if (div == 0)
89		div = 1;
90	if (div > 8)
91		div = 8;
92
93	/* Encode divisor to VIDC20 setting */
94	switch (div) {
95	case 1:	vidc->control |= VIDC20_CTRL_PIX_CK;  break;
96	case 2:	vidc->control |= VIDC20_CTRL_PIX_CK2; break;
97	case 3:	vidc->control |= VIDC20_CTRL_PIX_CK3; break;
98	case 4:	vidc->control |= VIDC20_CTRL_PIX_CK4; break;
99	case 5:	vidc->control |= VIDC20_CTRL_PIX_CK5; break;
100	case 6:	vidc->control |= VIDC20_CTRL_PIX_CK6; break;
101	case 7:	vidc->control |= VIDC20_CTRL_PIX_CK7; break;
102	case 8: vidc->control |= VIDC20_CTRL_PIX_CK8; break;
103	}
104
105	/*
106	 * With VRAM, the FIFO can be set to the highest possible setting
107	 * because there are no latency considerations for other memory
108	 * accesses. However, in 64 bit bus mode the FIFO preload value
109	 * must not be set to VIDC20_CTRL_FIFO_28 because this will let
110	 * the FIFO overflow. See VIDC20 manual page 33 (6.0 Setting the
111	 * FIFO preload value).
112	 */
113	if (current_par.using_vram) {
114		if (current_par.vram_half_sam == 2048)
115			vidc->control |= VIDC20_CTRL_FIFO_24;
116		else
117			vidc->control |= VIDC20_CTRL_FIFO_28;
118	} else {
119		unsigned long bandwidth = acornfb_bandwidth(var);
120
121		/* Encode bandwidth as VIDC20 setting */
122		if (bandwidth > 33334)		/* < 30.0MB/s */
123			vidc->control |= VIDC20_CTRL_FIFO_16;
124		else if (bandwidth > 26666)	/* < 37.5MB/s */
125			vidc->control |= VIDC20_CTRL_FIFO_20;
126		else if (bandwidth > 22222)	/* < 45.0MB/s */
127			vidc->control |= VIDC20_CTRL_FIFO_24;
128		else				/* > 45.0MB/s */
129			vidc->control |= VIDC20_CTRL_FIFO_28;
130	}
131
132	/* Find the PLL values */
133	vidc->pll_ctl = acornfb_vidc20_find_pll(var->pixclock / div);
134}
135
136#define acornfb_default_control()	(VIDC20_CTRL_PIX_VCLK)
137#define acornfb_default_econtrol()	(VIDC20_ECTL_DAC | VIDC20_ECTL_REG(3))
138