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