]>
Commit | Line | Data |
---|---|---|
fc4effc7 DV |
1 | /* |
2 | * Geode GX display controller. | |
3 | * | |
4 | * Copyright (C) 2005 Arcom Control Systems Ltd. | |
5 | * | |
6 | * Portions from AMD's original 2.4 driver: | |
7 | * Copyright (C) 2004 Advanced Micro Devices, Inc. | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License as published by * the | |
11 | * Free Software Foundation; either version 2 of the License, or * (at your | |
12 | * option) any later version. | |
13 | */ | |
14 | #include <linux/spinlock.h> | |
15 | #include <linux/fb.h> | |
16 | #include <linux/delay.h> | |
17 | #include <asm/io.h> | |
18 | #include <asm/div64.h> | |
19 | #include <asm/delay.h> | |
20 | ||
21 | #include "geodefb.h" | |
22 | #include "display_gx.h" | |
23 | ||
4c1979c8 | 24 | unsigned int gx_frame_buffer_size(void) |
fc4effc7 | 25 | { |
4c1979c8 JC |
26 | unsigned int val; |
27 | ||
28 | /* FB size is reported by a virtual register */ | |
29 | /* Virtual register class = 0x02 */ | |
30 | /* VG_MEM_SIZE(512Kb units) = 0x00 */ | |
31 | ||
32 | outw(0xFC53, 0xAC1C); | |
33 | outw(0x0200, 0xAC1C); | |
34 | ||
35 | val = (unsigned int)(inw(0xAC1E)) & 0xFFl; | |
36 | return (val << 19); | |
fc4effc7 DV |
37 | } |
38 | ||
39 | int gx_line_delta(int xres, int bpp) | |
40 | { | |
41 | /* Must be a multiple of 8 bytes. */ | |
42 | return (xres * (bpp >> 3) + 7) & ~0x7; | |
43 | } | |
44 | ||
45 | static void gx_set_mode(struct fb_info *info) | |
46 | { | |
47 | struct geodefb_par *par = info->par; | |
48 | u32 gcfg, dcfg; | |
49 | int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal; | |
50 | int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; | |
51 | ||
52 | /* Unlock the display controller registers. */ | |
53 | readl(par->dc_regs + DC_UNLOCK); | |
54 | writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); | |
55 | ||
56 | gcfg = readl(par->dc_regs + DC_GENERAL_CFG); | |
57 | dcfg = readl(par->dc_regs + DC_DISPLAY_CFG); | |
58 | ||
59 | /* Disable the timing generator. */ | |
60 | dcfg &= ~(DC_DCFG_TGEN); | |
61 | writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); | |
62 | ||
63 | /* Wait for pending memory requests before disabling the FIFO load. */ | |
64 | udelay(100); | |
65 | ||
66 | /* Disable FIFO load and compression. */ | |
67 | gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE); | |
68 | writel(gcfg, par->dc_regs + DC_GENERAL_CFG); | |
69 | ||
70 | /* Setup DCLK and its divisor. */ | |
71 | par->vid_ops->set_dclk(info); | |
72 | ||
73 | /* | |
74 | * Setup new mode. | |
75 | */ | |
76 | ||
77 | /* Clear all unused feature bits. */ | |
78 | gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE; | |
79 | dcfg = 0; | |
80 | ||
81 | /* Set FIFO priority (default 6/5) and enable. */ | |
82 | /* FIXME: increase fifo priority for 1280x1024 and higher modes? */ | |
83 | gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE; | |
84 | ||
85 | /* Framebuffer start offset. */ | |
86 | writel(0, par->dc_regs + DC_FB_ST_OFFSET); | |
87 | ||
88 | /* Line delta and line buffer length. */ | |
89 | writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH); | |
90 | writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2, | |
91 | par->dc_regs + DC_LINE_SIZE); | |
92 | ||
f378819a | 93 | |
fc4effc7 DV |
94 | /* Enable graphics and video data and unmask address lines. */ |
95 | dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M; | |
96 | ||
97 | /* Set pixel format. */ | |
98 | switch (info->var.bits_per_pixel) { | |
99 | case 8: | |
100 | dcfg |= DC_DCFG_DISP_MODE_8BPP; | |
101 | break; | |
102 | case 16: | |
103 | dcfg |= DC_DCFG_DISP_MODE_16BPP; | |
104 | dcfg |= DC_DCFG_16BPP_MODE_565; | |
105 | break; | |
106 | case 32: | |
107 | dcfg |= DC_DCFG_DISP_MODE_24BPP; | |
108 | dcfg |= DC_DCFG_PALB; | |
109 | break; | |
110 | } | |
111 | ||
112 | /* Enable timing generator. */ | |
113 | dcfg |= DC_DCFG_TGEN; | |
114 | ||
115 | /* Horizontal and vertical timings. */ | |
116 | hactive = info->var.xres; | |
117 | hblankstart = hactive; | |
118 | hsyncstart = hblankstart + info->var.right_margin; | |
119 | hsyncend = hsyncstart + info->var.hsync_len; | |
120 | hblankend = hsyncend + info->var.left_margin; | |
121 | htotal = hblankend; | |
122 | ||
123 | vactive = info->var.yres; | |
124 | vblankstart = vactive; | |
125 | vsyncstart = vblankstart + info->var.lower_margin; | |
126 | vsyncend = vsyncstart + info->var.vsync_len; | |
127 | vblankend = vsyncend + info->var.upper_margin; | |
128 | vtotal = vblankend; | |
129 | ||
130 | writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING); | |
131 | writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING); | |
132 | writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING); | |
133 | ||
134 | writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING); | |
135 | writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING); | |
136 | writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING); | |
137 | ||
138 | /* Write final register values. */ | |
139 | writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); | |
140 | writel(gcfg, par->dc_regs + DC_GENERAL_CFG); | |
141 | ||
142 | par->vid_ops->configure_display(info); | |
143 | ||
144 | /* Relock display controller registers */ | |
145 | writel(0, par->dc_regs + DC_UNLOCK); | |
146 | } | |
147 | ||
148 | static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, | |
149 | unsigned red, unsigned green, unsigned blue) | |
150 | { | |
151 | struct geodefb_par *par = info->par; | |
152 | int val; | |
153 | ||
154 | /* Hardware palette is in RGB 8-8-8 format. */ | |
155 | val = (red << 8) & 0xff0000; | |
156 | val |= (green) & 0x00ff00; | |
157 | val |= (blue >> 8) & 0x0000ff; | |
158 | ||
159 | writel(regno, par->dc_regs + DC_PAL_ADDRESS); | |
160 | writel(val, par->dc_regs + DC_PAL_DATA); | |
161 | } | |
162 | ||
163 | struct geode_dc_ops gx_dc_ops = { | |
164 | .set_mode = gx_set_mode, | |
165 | .set_palette_reg = gx_set_hw_palette_reg, | |
166 | }; |