1/*
2 *  linux/include/asm-arm/arch-rpc/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
15static inline int
16acornfb_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 */
44static inline u_int
45acornfb_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
81static inline void
82acornfb_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