diff options
Diffstat (limited to 'drivers/video/tx3912fb.c')
-rw-r--r-- | drivers/video/tx3912fb.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c new file mode 100644 index 000000000000..39d9ca71856b --- /dev/null +++ b/drivers/video/tx3912fb.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * drivers/video/tx3912fb.c | ||
3 | * | ||
4 | * Copyright (C) 1999 Harald Koerfgen | ||
5 | * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com) | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file COPYING in the main directory of this archive for | ||
9 | * more details. | ||
10 | * | ||
11 | * Framebuffer for LCD controller in TMPR3912/05 and PR31700 processors | ||
12 | */ | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/tty.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/pm.h> | ||
22 | #include <linux/fb.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <asm/bootinfo.h> | ||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/tx3912.h> | ||
27 | #include <video/tx3912.h> | ||
28 | |||
29 | /* | ||
30 | * Frame buffer, palette and console structures | ||
31 | */ | ||
32 | static struct fb_info fb_info; | ||
33 | static u32 cfb8[16]; | ||
34 | |||
35 | static struct fb_fix_screeninfo tx3912fb_fix __initdata = { | ||
36 | .id = "tx3912fb", | ||
37 | .smem_len = ((240 * 320)/2), | ||
38 | .type = FB_TYPE_PACKED_PIXELS, | ||
39 | .visual = FB_VISUAL_TRUECOLOR, | ||
40 | .xpanstep = 1, | ||
41 | .ypanstep = 1, | ||
42 | .ywrapstep = 1, | ||
43 | .accel = FB_ACCEL_NONE, | ||
44 | }; | ||
45 | |||
46 | static struct fb_var_screeninfo tx3912fb_var = { | ||
47 | .xres = 240, | ||
48 | .yres = 320, | ||
49 | .xres_virtual = 240, | ||
50 | .yres_virtual = 320, | ||
51 | .bits_per_pixel =4, | ||
52 | .red = { 0, 4, 0 }, /* ??? */ | ||
53 | .green = { 0, 4, 0 }, | ||
54 | .blue = { 0, 4, 0 }, | ||
55 | .activate = FB_ACTIVATE_NOW, | ||
56 | .width = -1, | ||
57 | .height = -1, | ||
58 | .pixclock = 20000, | ||
59 | .left_margin = 64, | ||
60 | .right_margin = 64, | ||
61 | .upper_margin = 32, | ||
62 | .lower_margin = 32, | ||
63 | .hsync_len = 64, | ||
64 | .vsync_len = 2, | ||
65 | .vmode = FB_VMODE_NONINTERLACED, | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * Interface used by the world | ||
70 | */ | ||
71 | int tx3912fb_init(void); | ||
72 | |||
73 | static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, | ||
74 | u_int blue, u_int transp, | ||
75 | struct fb_info *info); | ||
76 | |||
77 | /* | ||
78 | * Macros | ||
79 | */ | ||
80 | #define get_line_length(xres_virtual, bpp) \ | ||
81 | (u_long) (((int) xres_virtual * (int) bpp + 7) >> 3) | ||
82 | |||
83 | /* | ||
84 | * Frame buffer operations structure used by console driver | ||
85 | */ | ||
86 | static struct fb_ops tx3912fb_ops = { | ||
87 | .owner = THIS_MODULE, | ||
88 | .fb_setcolreg = tx3912fb_setcolreg, | ||
89 | .fb_fillrect = cfb_fillrect, | ||
90 | .fb_copyarea = cfb_copyarea, | ||
91 | .fb_imageblit = cfb_imageblit, | ||
92 | .fb_cursor = soft_cursor, | ||
93 | }; | ||
94 | |||
95 | static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
96 | { | ||
97 | /* | ||
98 | * Memory limit | ||
99 | */ | ||
100 | line_length = | ||
101 | get_line_length(var->xres_virtual, var->bits_per_pixel); | ||
102 | if ((line_length * var->yres_virtual) > info->fix.smem_len) | ||
103 | return -ENOMEM; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int tx3912fb_set_par(struct fb_info *info) | ||
109 | { | ||
110 | u_long tx3912fb_paddr = 0; | ||
111 | |||
112 | /* Disable the video logic */ | ||
113 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
114 | ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | ||
115 | TX3912_VIDEO_CTRL1); | ||
116 | udelay(200); | ||
117 | |||
118 | /* Set start address for DMA transfer */ | ||
119 | outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3); | ||
120 | |||
121 | /* Set end address for DMA transfer */ | ||
122 | outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4); | ||
123 | |||
124 | /* Set the pixel depth */ | ||
125 | switch (info->var.bits_per_pixel) { | ||
126 | case 1: | ||
127 | /* Monochrome */ | ||
128 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
129 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | ||
130 | info->fix.visual = FB_VISUAL_MONO10; | ||
131 | break; | ||
132 | case 4: | ||
133 | /* 4-bit gray */ | ||
134 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
135 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | ||
136 | outl(inl(TX3912_VIDEO_CTRL1) | | ||
137 | TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY, | ||
138 | TX3912_VIDEO_CTRL1); | ||
139 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
140 | break; | ||
141 | case 8: | ||
142 | /* 8-bit color */ | ||
143 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
144 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | ||
145 | outl(inl(TX3912_VIDEO_CTRL1) | | ||
146 | TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR, | ||
147 | TX3912_VIDEO_CTRL1); | ||
148 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
149 | break; | ||
150 | case 2: | ||
151 | default: | ||
152 | /* 2-bit gray */ | ||
153 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
154 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | ||
155 | outl(inl(TX3912_VIDEO_CTRL1) | | ||
156 | TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY, | ||
157 | TX3912_VIDEO_CTRL1); | ||
158 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
159 | break; | ||
160 | } | ||
161 | |||
162 | /* Enable the video clock */ | ||
163 | outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK, | ||
164 | TX3912_CLK_CTRL); | ||
165 | |||
166 | /* Unfreeze video logic and enable DF toggle */ | ||
167 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
168 | ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | | ||
169 | TX3912_VIDEO_CTRL1_DFMODE) | ||
170 | , TX3912_VIDEO_CTRL1); | ||
171 | udelay(200); | ||
172 | |||
173 | /* Enable the video logic */ | ||
174 | outl(inl(TX3912_VIDEO_CTRL1) | | ||
175 | (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | ||
176 | TX3912_VIDEO_CTRL1); | ||
177 | |||
178 | info->fix.line_length = get_line_length(var->xres_virtual, | ||
179 | var->bits_per_pixel); | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Set a single color register | ||
184 | */ | ||
185 | static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, | ||
186 | u_int blue, u_int transp, | ||
187 | struct fb_info *info) | ||
188 | { | ||
189 | if (regno > 255) | ||
190 | return 1; | ||
191 | |||
192 | if (regno < 16) | ||
193 | ((u32 *)(info->pseudo_palette))[regno] = ((red & 0xe000) >> 8) | ||
194 | | ((green & 0xe000) >> 11) | ||
195 | | ((blue & 0xc000) >> 14); | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | int __init tx3912fb_setup(char *options); | ||
200 | |||
201 | /* | ||
202 | * Initialization of the framebuffer | ||
203 | */ | ||
204 | int __init tx3912fb_init(void) | ||
205 | { | ||
206 | u_long tx3912fb_paddr = 0; | ||
207 | int size = (info->var.bits_per_pixel == 8) ? 256 : 16; | ||
208 | char *option = NULL; | ||
209 | |||
210 | if (fb_get_options("tx3912fb", &option)) | ||
211 | return -ENODEV; | ||
212 | tx3912fb_setup(option); | ||
213 | |||
214 | /* Disable the video logic */ | ||
215 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
216 | ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | ||
217 | TX3912_VIDEO_CTRL1); | ||
218 | udelay(200); | ||
219 | |||
220 | /* Set start address for DMA transfer */ | ||
221 | outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3); | ||
222 | |||
223 | /* Set end address for DMA transfer */ | ||
224 | outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4); | ||
225 | |||
226 | /* Set the pixel depth */ | ||
227 | switch (tx3912fb_var.bits_per_pixel) { | ||
228 | case 1: | ||
229 | /* Monochrome */ | ||
230 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
231 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | ||
232 | tx3912fb_fix.visual = FB_VISUAL_MONO10; | ||
233 | break; | ||
234 | case 4: | ||
235 | /* 4-bit gray */ | ||
236 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
237 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | ||
238 | outl(inl(TX3912_VIDEO_CTRL1) | | ||
239 | TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY, | ||
240 | TX3912_VIDEO_CTRL1); | ||
241 | tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR; | ||
242 | tx3912fb_fix.grayscale = 1; | ||
243 | break; | ||
244 | case 8: | ||
245 | /* 8-bit color */ | ||
246 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
247 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | ||
248 | outl(inl(TX3912_VIDEO_CTRL1) | | ||
249 | TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR, | ||
250 | TX3912_VIDEO_CTRL1); | ||
251 | tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR; | ||
252 | break; | ||
253 | case 2: | ||
254 | default: | ||
255 | /* 2-bit gray */ | ||
256 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
257 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | ||
258 | outl(inl(TX3912_VIDEO_CTRL1) | | ||
259 | TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY, | ||
260 | TX3912_VIDEO_CTRL1); | ||
261 | tx3912fb_fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
262 | tx3912fb_fix.grayscale = 1; | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | /* Enable the video clock */ | ||
267 | outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK, | ||
268 | TX3912_CLK_CTRL); | ||
269 | |||
270 | /* Unfreeze video logic and enable DF toggle */ | ||
271 | outl(inl(TX3912_VIDEO_CTRL1) & | ||
272 | ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE), | ||
273 | TX3912_VIDEO_CTRL1); | ||
274 | udelay(200); | ||
275 | |||
276 | /* Clear the framebuffer */ | ||
277 | memset((void *) tx3912fb_fix.smem_start, 0xff, tx3912fb_fix.smem_len); | ||
278 | udelay(200); | ||
279 | |||
280 | /* Enable the video logic */ | ||
281 | outl(inl(TX3912_VIDEO_CTRL1) | | ||
282 | (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | ||
283 | TX3912_VIDEO_CTRL1); | ||
284 | |||
285 | /* | ||
286 | * Memory limit | ||
287 | */ | ||
288 | tx3912fb_fix.line_length = | ||
289 | get_line_length(tx3912fb_var.xres_virtual, tx3912fb_var.bits_per_pixel); | ||
290 | if ((tx3912fb_fix.line_length * tx3912fb_var.yres_virtual) > tx3912fb_fix.smem_len) | ||
291 | return -ENOMEM; | ||
292 | |||
293 | fb_info.fbops = &tx3912fb_ops; | ||
294 | fb_info.var = tx3912fb_var; | ||
295 | fb_info.fix = tx3912fb_fix; | ||
296 | fb_info.pseudo_palette = pseudo_palette; | ||
297 | fb_info.flags = FBINFO_DEFAULT; | ||
298 | |||
299 | /* Clear the framebuffer */ | ||
300 | memset((void *) fb_info.fix.smem_start, 0xff, fb_info.fix.smem_len); | ||
301 | udelay(200); | ||
302 | |||
303 | fb_alloc_cmap(&info->cmap, size, 0); | ||
304 | |||
305 | if (register_framebuffer(&fb_info) < 0) | ||
306 | return -1; | ||
307 | |||
308 | printk(KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n", | ||
309 | fb_info.node, (u_int) (fb_info.fix.smem_len >> 10)); | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | int __init tx3912fb_setup(char *options) | ||
314 | { | ||
315 | char *this_opt; | ||
316 | |||
317 | if (!options || !*options) | ||
318 | return 0; | ||
319 | |||
320 | while ((this_opt = strsep(&options, ","))) { | ||
321 | if (!strncmp(options, "bpp:", 4)) | ||
322 | tx3912fb_var.bits_per_pixel = simple_strtoul(options+4, NULL, 0); | ||
323 | } | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | module_init(tx3912fb_init); | ||
328 | MODULE_LICENSE("GPL"); | ||