blob: d904da44e1aacf280497bb174f4caccaf7bf4cb8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 */
32static struct fb_info fb_info;
33static u32 cfb8[16];
34
35static 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
46static 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 */
71int tx3912fb_init(void);
72
73static 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 */
86static 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,
Linus Torvalds1da177e2005-04-16 15:20:36 -070092};
93
94static 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
107static 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 */
184static 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
198int __init tx3912fb_setup(char *options);
199
200/*
201 * Initialization of the framebuffer
202 */
203int __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
312int __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
326module_init(tx3912fb_init);
327MODULE_LICENSE("GPL");