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