Commit | Line | Data |
---|---|---|
1da177e4 LT |
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, | |
1da177e4 LT |
92 | }; |
93 | ||
94 | static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |
95 | { | |
96 | /* | |
97 | * Memory limit | |
98 | */ | |
99 | line_length = | |
100 | get_line_length(var->xres_virtual, var->bits_per_pixel); | |
101 | if ((line_length * var->yres_virtual) > info->fix.smem_len) | |
102 | return -ENOMEM; | |
103 | ||
104 | return 0; | |
105 | } | |
106 | ||
107 | static int tx3912fb_set_par(struct fb_info *info) | |
108 | { | |
109 | u_long tx3912fb_paddr = 0; | |
110 | ||
111 | /* Disable the video logic */ | |
112 | outl(inl(TX3912_VIDEO_CTRL1) & | |
113 | ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | |
114 | TX3912_VIDEO_CTRL1); | |
115 | udelay(200); | |
116 | ||
117 | /* Set start address for DMA transfer */ | |
118 | outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3); | |
119 | ||
120 | /* Set end address for DMA transfer */ | |
121 | outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4); | |
122 | ||
123 | /* Set the pixel depth */ | |
124 | switch (info->var.bits_per_pixel) { | |
125 | case 1: | |
126 | /* Monochrome */ | |
127 | outl(inl(TX3912_VIDEO_CTRL1) & | |
128 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
129 | info->fix.visual = FB_VISUAL_MONO10; | |
130 | break; | |
131 | case 4: | |
132 | /* 4-bit gray */ | |
133 | outl(inl(TX3912_VIDEO_CTRL1) & | |
134 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
135 | outl(inl(TX3912_VIDEO_CTRL1) | | |
136 | TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY, | |
137 | TX3912_VIDEO_CTRL1); | |
138 | info->fix.visual = FB_VISUAL_TRUECOLOR; | |
139 | break; | |
140 | case 8: | |
141 | /* 8-bit color */ | |
142 | outl(inl(TX3912_VIDEO_CTRL1) & | |
143 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
144 | outl(inl(TX3912_VIDEO_CTRL1) | | |
145 | TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR, | |
146 | TX3912_VIDEO_CTRL1); | |
147 | info->fix.visual = FB_VISUAL_TRUECOLOR; | |
148 | break; | |
149 | case 2: | |
150 | default: | |
151 | /* 2-bit gray */ | |
152 | outl(inl(TX3912_VIDEO_CTRL1) & | |
153 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
154 | outl(inl(TX3912_VIDEO_CTRL1) | | |
155 | TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY, | |
156 | TX3912_VIDEO_CTRL1); | |
157 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | |
158 | break; | |
159 | } | |
160 | ||
161 | /* Enable the video clock */ | |
162 | outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK, | |
163 | TX3912_CLK_CTRL); | |
164 | ||
165 | /* Unfreeze video logic and enable DF toggle */ | |
166 | outl(inl(TX3912_VIDEO_CTRL1) & | |
167 | ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | | |
168 | TX3912_VIDEO_CTRL1_DFMODE) | |
169 | , TX3912_VIDEO_CTRL1); | |
170 | udelay(200); | |
171 | ||
172 | /* Enable the video logic */ | |
173 | outl(inl(TX3912_VIDEO_CTRL1) | | |
174 | (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | |
175 | TX3912_VIDEO_CTRL1); | |
176 | ||
177 | info->fix.line_length = get_line_length(var->xres_virtual, | |
178 | var->bits_per_pixel); | |
179 | } | |
180 | ||
181 | /* | |
182 | * Set a single color register | |
183 | */ | |
184 | static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, | |
185 | u_int blue, u_int transp, | |
186 | struct fb_info *info) | |
187 | { | |
188 | if (regno > 255) | |
189 | return 1; | |
190 | ||
191 | if (regno < 16) | |
192 | ((u32 *)(info->pseudo_palette))[regno] = ((red & 0xe000) >> 8) | |
193 | | ((green & 0xe000) >> 11) | |
194 | | ((blue & 0xc000) >> 14); | |
195 | return 0; | |
196 | } | |
197 | ||
198 | int __init tx3912fb_setup(char *options); | |
199 | ||
200 | /* | |
201 | * Initialization of the framebuffer | |
202 | */ | |
203 | int __init tx3912fb_init(void) | |
204 | { | |
205 | u_long tx3912fb_paddr = 0; | |
206 | int size = (info->var.bits_per_pixel == 8) ? 256 : 16; | |
207 | char *option = NULL; | |
208 | ||
209 | if (fb_get_options("tx3912fb", &option)) | |
210 | return -ENODEV; | |
211 | tx3912fb_setup(option); | |
212 | ||
213 | /* Disable the video logic */ | |
214 | outl(inl(TX3912_VIDEO_CTRL1) & | |
215 | ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | |
216 | TX3912_VIDEO_CTRL1); | |
217 | udelay(200); | |
218 | ||
219 | /* Set start address for DMA transfer */ | |
220 | outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3); | |
221 | ||
222 | /* Set end address for DMA transfer */ | |
223 | outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4); | |
224 | ||
225 | /* Set the pixel depth */ | |
226 | switch (tx3912fb_var.bits_per_pixel) { | |
227 | case 1: | |
228 | /* Monochrome */ | |
229 | outl(inl(TX3912_VIDEO_CTRL1) & | |
230 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
231 | tx3912fb_fix.visual = FB_VISUAL_MONO10; | |
232 | break; | |
233 | case 4: | |
234 | /* 4-bit gray */ | |
235 | outl(inl(TX3912_VIDEO_CTRL1) & | |
236 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
237 | outl(inl(TX3912_VIDEO_CTRL1) | | |
238 | TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY, | |
239 | TX3912_VIDEO_CTRL1); | |
240 | tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR; | |
241 | tx3912fb_fix.grayscale = 1; | |
242 | break; | |
243 | case 8: | |
244 | /* 8-bit color */ | |
245 | outl(inl(TX3912_VIDEO_CTRL1) & | |
246 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
247 | outl(inl(TX3912_VIDEO_CTRL1) | | |
248 | TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR, | |
249 | TX3912_VIDEO_CTRL1); | |
250 | tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR; | |
251 | break; | |
252 | case 2: | |
253 | default: | |
254 | /* 2-bit gray */ | |
255 | outl(inl(TX3912_VIDEO_CTRL1) & | |
256 | ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1); | |
257 | outl(inl(TX3912_VIDEO_CTRL1) | | |
258 | TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY, | |
259 | TX3912_VIDEO_CTRL1); | |
260 | tx3912fb_fix.visual = FB_VISUAL_PSEUDOCOLOR; | |
261 | tx3912fb_fix.grayscale = 1; | |
262 | break; | |
263 | } | |
264 | ||
265 | /* Enable the video clock */ | |
266 | outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK, | |
267 | TX3912_CLK_CTRL); | |
268 | ||
269 | /* Unfreeze video logic and enable DF toggle */ | |
270 | outl(inl(TX3912_VIDEO_CTRL1) & | |
271 | ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE), | |
272 | TX3912_VIDEO_CTRL1); | |
273 | udelay(200); | |
274 | ||
275 | /* Clear the framebuffer */ | |
276 | memset((void *) tx3912fb_fix.smem_start, 0xff, tx3912fb_fix.smem_len); | |
277 | udelay(200); | |
278 | ||
279 | /* Enable the video logic */ | |
280 | outl(inl(TX3912_VIDEO_CTRL1) | | |
281 | (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON), | |
282 | TX3912_VIDEO_CTRL1); | |
283 | ||
284 | /* | |
285 | * Memory limit | |
286 | */ | |
287 | tx3912fb_fix.line_length = | |
288 | get_line_length(tx3912fb_var.xres_virtual, tx3912fb_var.bits_per_pixel); | |
289 | if ((tx3912fb_fix.line_length * tx3912fb_var.yres_virtual) > tx3912fb_fix.smem_len) | |
290 | return -ENOMEM; | |
291 | ||
292 | fb_info.fbops = &tx3912fb_ops; | |
293 | fb_info.var = tx3912fb_var; | |
294 | fb_info.fix = tx3912fb_fix; | |
295 | fb_info.pseudo_palette = pseudo_palette; | |
296 | fb_info.flags = FBINFO_DEFAULT; | |
297 | ||
298 | /* Clear the framebuffer */ | |
299 | memset((void *) fb_info.fix.smem_start, 0xff, fb_info.fix.smem_len); | |
300 | udelay(200); | |
301 | ||
302 | fb_alloc_cmap(&info->cmap, size, 0); | |
303 | ||
304 | if (register_framebuffer(&fb_info) < 0) | |
305 | return -1; | |
306 | ||
307 | printk(KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n", | |
308 | fb_info.node, (u_int) (fb_info.fix.smem_len >> 10)); | |
309 | return 0; | |
310 | } | |
311 | ||
312 | int __init tx3912fb_setup(char *options) | |
313 | { | |
314 | char *this_opt; | |
315 | ||
316 | if (!options || !*options) | |
317 | return 0; | |
318 | ||
319 | while ((this_opt = strsep(&options, ","))) { | |
320 | if (!strncmp(options, "bpp:", 4)) | |
321 | tx3912fb_var.bits_per_pixel = simple_strtoul(options+4, NULL, 0); | |
322 | } | |
323 | return 0; | |
324 | } | |
325 | ||
326 | module_init(tx3912fb_init); | |
327 | MODULE_LICENSE("GPL"); |