aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-arm/arch-rpc/acornfb.h
blob: ecb7733a09499a0179c3c35f867857c287a47d02 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 *  linux/include/asm-arm/arch-rpc/acornfb.h
 *
 *  Copyright (C) 1999 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *  AcornFB architecture specific code
 */

#define acornfb_bandwidth(var) ((var)->pixclock * 8 / (var)->bits_per_pixel)

static inline int
acornfb_valid_pixrate(struct fb_var_screeninfo *var)
{
	u_long limit;

	if (!var->pixclock)
		return 0;

	/*
	 * Limits below are taken from RISC OS bandwidthlimit file
	 */
	if (current_par.using_vram) {
		if (current_par.vram_half_sam == 2048)
			limit = 6578;
		else
			limit = 13157;
	} else {
		limit = 26315;
	}

	return acornfb_bandwidth(var) >= limit;
}

/*
 * Try to find the best PLL parameters for the pixel clock.
 * This algorithm seems to give best predictable results,
 * and produces the same values as detailed in the VIDC20
 * data sheet.
 */
static inline u_int
acornfb_vidc20_find_pll(u_int pixclk)
{
	u_int r, best_r = 2, best_v = 2;
	int best_d = 0x7fffffff;

	for (r = 2; r <= 32; r++) {
		u_int rr, v, p;
		int d;

		rr = 41667 * r;

		v = (rr + pixclk / 2) / pixclk;

		if (v > 32 || v < 2)
			continue;

		p = (rr + v / 2) / v;

		d = pixclk - p;

		if (d < 0)
			d = -d;

		if (d < best_d) {
			best_d = d;
			best_v = v - 1;
			best_r = r - 1;
		}

		if (d == 0)
			break;
	}

	return best_v << 8 | best_r;
}

static inline void
acornfb_vidc20_find_rates(struct vidc_timing *vidc,
			  struct fb_var_screeninfo *var)
{
	u_int div;

	/* Select pixel-clock divisor to keep PLL in range */
	div = var->pixclock / 9090; /*9921*/

	/* Limit divisor */
	if (div == 0)
		div = 1;
	if (div > 8)
		div = 8;

	/* Encode divisor to VIDC20 setting */
	switch (div) {
	case 1:	vidc->control |= VIDC20_CTRL_PIX_CK;  break;
	case 2:	vidc->control |= VIDC20_CTRL_PIX_CK2; break;
	case 3:	vidc->control |= VIDC20_CTRL_PIX_CK3; break;
	case 4:	vidc->control |= VIDC20_CTRL_PIX_CK4; break;
	case 5:	vidc->control |= VIDC20_CTRL_PIX_CK5; break;
	case 6:	vidc->control |= VIDC20_CTRL_PIX_CK6; break;
	case 7:	vidc->control |= VIDC20_CTRL_PIX_CK7; break;
	case 8: vidc->control |= VIDC20_CTRL_PIX_CK8; break;
	}

	/*
	 * With VRAM, the FIFO can be set to the highest possible setting
	 * because there are no latency considerations for other memory
	 * accesses. However, in 64 bit bus mode the FIFO preload value
	 * must not be set to VIDC20_CTRL_FIFO_28 because this will let
	 * the FIFO overflow. See VIDC20 manual page 33 (6.0 Setting the
	 * FIFO preload value).
	 */
	if (current_par.using_vram) {
		if (current_par.vram_half_sam == 2048)
			vidc->control |= VIDC20_CTRL_FIFO_24;
		else
			vidc->control |= VIDC20_CTRL_FIFO_28;
	} else {
		unsigned long bandwidth = acornfb_bandwidth(var);

		/* Encode bandwidth as VIDC20 setting */
		if (bandwidth > 33334)		/* < 30.0MB/s */
			vidc->control |= VIDC20_CTRL_FIFO_16;
		else if (bandwidth > 26666)	/* < 37.5MB/s */
			vidc->control |= VIDC20_CTRL_FIFO_20;
		else if (bandwidth > 22222)	/* < 45.0MB/s */
			vidc->control |= VIDC20_CTRL_FIFO_24;
		else				/* > 45.0MB/s */
			vidc->control |= VIDC20_CTRL_FIFO_28;
	}

	/* Find the PLL values */
	vidc->pll_ctl = acornfb_vidc20_find_pll(var->pixclock / div);
}

#define acornfb_default_control()	(VIDC20_CTRL_PIX_VCLK)
#define acornfb_default_econtrol()	(VIDC20_ECTL_DAC | VIDC20_ECTL_REG(3))