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 
12 static inline int
acornfb_valid_pixrate(struct fb_var_screeninfo * var)13 acornfb_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  */
41 static inline u_int
acornfb_vidc20_find_pll(u_int pixclk)42 acornfb_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 
78 static inline void
acornfb_vidc20_find_rates(struct vidc_timing * vidc,struct fb_var_screeninfo * var)79 acornfb_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