ipaq_lcd.c revision 1.12 1 /* $NetBSD: ipaq_lcd.c,v 1.12 2004/12/12 21:03:06 abs Exp $ */
2
3 /*
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ichiro FUKUHARA (ichiro (at) ichiro.org).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: ipaq_lcd.c,v 1.12 2004/12/12 21:03:06 abs Exp $");
41
42 #define IPAQ_LCD_DEBUG
43
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/time.h>
49 #include <sys/device.h>
50
51 #include <uvm/uvm_extern.h>
52
53 #include <dev/wscons/wsconsio.h>
54
55 #include <machine/bootinfo.h>
56 #include <machine/bus.h>
57 #include <machine/intr.h>
58 #include <arm/cpufunc.h>
59 #include <arm/arm32/katelib.h>
60
61 #include <hpcarm/sa11x0/sa11x0_reg.h>
62 #include <hpcarm/sa11x0/sa11x0_gpioreg.h>
63
64 #include <hpcarm/dev/ipaq_gpioreg.h>
65 #include <hpcarm/dev/ipaq_saipvar.h>
66 #include <hpcarm/dev/ipaq_lcdreg.h>
67 #include <hpcarm/dev/ipaq_lcdvar.h>
68
69 #ifdef IPAQ_LCD_DEBUG
70 #define DPRINTFN(n, x) if (ipaqlcddebug > (n)) printf x
71 int ipaqlcddebug = 0xff;
72 #else
73 #define DPRINTFN(n, x)
74 #endif
75 #define DPRINTF(x) DPRINTFN(0, x)
76
77 static int ipaqlcd_match(struct device *, struct cfdata *, void *);
78 static void ipaqlcd_attach(struct device *, struct device *, void *);
79 static void ipaqlcd_init(struct ipaqlcd_softc *);
80 static int ipaqlcd_fbinit(struct ipaqlcd_softc *);
81 static int ipaqlcd_ioctl(void *, u_long, caddr_t, int, struct proc *);
82 static paddr_t ipaqlcd_mmap(void *, off_t offset, int);
83
84 #if defined __mips__ || defined __sh__ || defined __arm__
85 #define __BTOP(x) ((paddr_t)(x) >> PGSHIFT)
86 #define __PTOB(x) ((paddr_t)(x) << PGSHIFT)
87 #else
88 #error "define btop, ptob."
89 #endif
90
91 CFATTACH_DECL(ipaqlcd, sizeof(struct ipaqlcd_softc),
92 ipaqlcd_match, ipaqlcd_attach, NULL, NULL);
93
94 struct hpcfb_accessops ipaqlcd_ha = {
95 ipaqlcd_ioctl, ipaqlcd_mmap
96 };
97 static int console_flag = 0;
98
99 static int
100 ipaqlcd_match(parent, match, aux)
101 struct device *parent;
102 struct cfdata *match;
103 void *aux;
104 {
105 return (1);
106 }
107
108 void
109 ipaqlcd_attach(parent, self, aux)
110 struct device *parent;
111 struct device *self;
112 void *aux;
113 {
114 struct ipaqlcd_softc *sc = (struct ipaqlcd_softc*)self;
115 struct hpcfb_attach_args ha;
116 struct ipaq_softc *psc = (struct ipaq_softc *)parent;
117
118 sc->sc_iot = psc->sc_iot;
119 sc->sc_parent = (struct ipaq_softc *)parent;
120
121 ipaqlcd_init(sc);
122 ipaqlcd_fbinit(sc);
123
124 printf("\n");
125 printf("%s: iPAQ internal LCD controller\n", sc->sc_dev.dv_xname);
126
127 DPRINTF(("framebuffer_baseaddr=%lx\n", (u_long)bootinfo->fb_addr));
128
129 ha.ha_console = console_flag;
130 ha.ha_accessops = &ipaqlcd_ha;
131 ha.ha_accessctx = sc;
132 ha.ha_curfbconf = 0;
133 ha.ha_nfbconf = 1;
134 ha.ha_fbconflist = &sc->sc_fbconf;
135 ha.ha_curdspconf = 0;
136 ha.ha_ndspconf = 1;
137 ha.ha_dspconflist = &sc->sc_dspconf;
138
139 config_found(&sc->sc_dev, &ha, hpcfbprint);
140 }
141
142 void
143 ipaqlcd_init(sc)
144 struct ipaqlcd_softc *sc;
145 {
146 /* Initialization of Extended GPIO */
147 sc->sc_parent->ipaq_egpio |= EGPIO_LCD_INIT;
148 bus_space_write_2(sc->sc_iot, sc->sc_parent->sc_egpioh,
149 0, sc->sc_parent->ipaq_egpio);
150
151 if (bus_space_map(sc->sc_iot, SALCD_BASE, SALCD_NPORTS,
152 0, &sc->sc_ioh))
153 panic("ipaqlcd_init:Cannot map registers");
154
155 (u_long)bootinfo->fb_addr =
156 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_BA1);
157
158 /*
159 * Initialize LCD Control Register 0 - 3
160 * must initialize DMA Channel Base Address Register
161 * before enabling LCD(LEN = 1)
162 */
163 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
164 SALCD_CR1, IPAQ_LCCR1);
165 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
166 SALCD_CR2, IPAQ_LCCR2);
167 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
168 SALCD_CR3, IPAQ_LCCR3);
169 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
170 SALCD_CR0, IPAQ_LCCR0);
171
172 DPRINTF(("\n"
173 "DMA_BASE= %08x : DMA_CUR = %08x \n"
174 "LCCR0 = %08x : LCCR1 = %08x \n"
175 "LCCR2 = %08x : LCCR3 = %08x",
176 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_BA1),
177 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CA1),
178 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR0),
179 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR1),
180 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR2),
181 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR3)));
182
183 }
184
185 int
186 ipaqlcd_fbinit(sc)
187 struct ipaqlcd_softc *sc;
188 {
189 struct hpcfb_fbconf *fb;
190
191 fb = &sc->sc_fbconf;
192
193 /* Initialize fb */
194 memset(fb, 0, sizeof(*fb));
195
196 fb->hf_conf_index = 0; /* configuration index */
197 fb->hf_nconfs = 1;
198 strcpy(fb->hf_name, "built-in video");
199 strcpy(fb->hf_conf_name, "LCD");
200 /* configuration name */
201 fb->hf_height = bootinfo->fb_height;
202 fb->hf_width = bootinfo->fb_width;
203
204 if (bus_space_map(sc->sc_iot, (bus_addr_t)bootinfo->fb_addr,
205 bootinfo->fb_height * bootinfo->fb_line_bytes,
206 0, &fb->hf_baseaddr)) {
207 printf("unable to map framebuffer\n");
208 return (-1);
209 }
210
211 fb->hf_offset = (u_long)bootinfo->fb_addr -
212 __PTOB(__BTOP(bootinfo->fb_addr));
213 /* frame buffer start offset */
214 fb->hf_bytes_per_line = bootinfo->fb_line_bytes;
215 fb->hf_nplanes = 1;
216 fb->hf_bytes_per_plane = bootinfo->fb_height *
217 bootinfo->fb_line_bytes;
218
219 fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
220 fb->hf_access_flags |= HPCFB_ACCESS_WORD;
221 fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
222
223 switch (bootinfo->fb_type) {
224 /*
225 * gray scale
226 */
227 case BIFB_D2_M2L_3:
228 case BIFB_D2_M2L_3x2:
229 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
230 case BIFB_D2_M2L_0:
231 case BIFB_D2_M2L_0x2:
232 fb->hf_class = HPCFB_CLASS_GRAYSCALE;
233 break;
234 case BIFB_D4_M2L_F:
235 case BIFB_D4_M2L_Fx2:
236 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
237 case BIFB_D4_M2L_0:
238 case BIFB_D4_M2L_0x2:
239 fb->hf_class = HPCFB_CLASS_GRAYSCALE;
240 break;
241 /*
242 * indexed color
243 */
244 case BIFB_D8_FF:
245 case BIFB_D8_00:
246 fb->hf_offset = 0x200;
247 break;
248 /*
249 * RGB color
250 */
251 case BIFB_D16_FFFF:
252 case BIFB_D16_0000:
253 fb->hf_class = HPCFB_CLASS_RGBCOLOR;
254 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
255 fb->hf_order_flags = HPCFB_REVORDER_BYTE;
256 fb->hf_pack_width = 16;
257 fb->hf_pixels_per_pack = 1;
258 fb->hf_pixel_width = 16;
259
260 fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
261 fb->hf_u.hf_rgb.hf_flags = 0;
262 /* reserved for future use */
263 fb->hf_u.hf_rgb.hf_red_width = 5;
264 fb->hf_u.hf_rgb.hf_red_shift = 11;
265 fb->hf_u.hf_rgb.hf_green_width = 6;
266 fb->hf_u.hf_rgb.hf_green_shift = 5;
267 fb->hf_u.hf_rgb.hf_blue_width = 5;
268 fb->hf_u.hf_rgb.hf_blue_shift = 0;
269 fb->hf_u.hf_rgb.hf_alpha_width = 0;
270 fb->hf_u.hf_rgb.hf_alpha_shift = 0;
271 break;
272 default :
273 printf("unknown type (=%d).\n", bootinfo->fb_type);
274 return (-1);
275 break;
276 }
277
278 return(0);
279 }
280
281 int
282 ipaqlcd_ioctl(v, cmd, data, flag, p)
283 void *v;
284 u_long cmd;
285 caddr_t data;
286 int flag;
287 struct proc *p;
288 {
289 struct ipaqlcd_softc *sc = (struct ipaqlcd_softc *)v;
290 struct hpcfb_fbconf *fbconf;
291 struct hpcfb_dspconf *dspconf;
292 struct wsdisplay_cmap *cmap;
293 struct wsdisplay_param *dispparam;
294
295 switch (cmd) {
296 case WSDISPLAYIO_GETCMAP:
297 cmap = (struct wsdisplay_cmap*)data;
298
299 if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
300 sc->sc_fbconf.hf_pack_width != 8 ||
301 256 <= cmap->index ||
302 256 < (cmap->index + cmap->count))
303 return (EINVAL);
304 return (0);
305 case WSDISPLAYIO_PUTCMAP:
306 return (EINVAL);
307 case WSDISPLAYIO_GETPARAM:
308 dispparam = (struct wsdisplay_param*)data;
309 switch (dispparam->param) {
310 case WSDISPLAYIO_PARAM_BACKLIGHT:
311 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BACKLIGHT\n"));
312 return (EINVAL);
313 case WSDISPLAYIO_PARAM_CONTRAST:
314 DPRINTF(("ipaqlcd_ioctl: GETPARAM:CONTRAST\n"));
315 return (EINVAL);
316 case WSDISPLAYIO_PARAM_BRIGHTNESS:
317 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BRIGHTNESS\n"));
318 return (EINVAL);
319 default:
320 return (EINVAL);
321 }
322 return (0);
323 case WSDISPLAYIO_SETPARAM:
324 dispparam = (struct wsdisplay_param*)data;
325 switch (dispparam->param) {
326 case WSDISPLAYIO_PARAM_BACKLIGHT:
327 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BACKLIGHT\n"));
328 return (EINVAL);
329 case WSDISPLAYIO_PARAM_CONTRAST:
330 DPRINTF(("ipaqlcd_ioctl: GETPARAM:CONTRAST\n"));
331 return (EINVAL);
332 case WSDISPLAYIO_PARAM_BRIGHTNESS:
333 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BRIGHTNESS\n"));
334 return (EINVAL);
335 default:
336 return (EINVAL);
337 }
338 return (0);
339
340 case HPCFBIO_GCONF:
341 fbconf = (struct hpcfb_fbconf *)data;
342 if (fbconf->hf_conf_index != 0 &&
343 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
344 return (EINVAL);
345 }
346 *fbconf = sc->sc_fbconf; /* structure assignment */
347 return (0);
348 case HPCFBIO_SCONF:
349 fbconf = (struct hpcfb_fbconf *)data;
350 if (fbconf->hf_conf_index != 0 &&
351 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
352 return (EINVAL);
353 }
354 /*
355 * nothing to do because we have only one configuration
356 */
357 return (0);
358 case HPCFBIO_GDSPCONF:
359 dspconf = (struct hpcfb_dspconf *)data;
360 if ((dspconf->hd_unit_index != 0 &&
361 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
362 (dspconf->hd_conf_index != 0 &&
363 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
364 return (EINVAL);
365 }
366 *dspconf = sc->sc_dspconf; /* structure assignment */
367 return (0);
368 case HPCFBIO_SDSPCONF:
369 dspconf = (struct hpcfb_dspconf *)data;
370 if ((dspconf->hd_unit_index != 0 &&
371 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
372 (dspconf->hd_conf_index != 0 &&
373 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
374 return (EINVAL);
375 }
376 /*
377 * nothing to do
378 * because we have only one unit and one configuration
379 */
380 return (0);
381
382 case HPCFBIO_GOP:
383 case HPCFBIO_SOP:
384 return (EINVAL);
385 }
386 return (EPASSTHROUGH);
387 }
388
389 paddr_t
390 ipaqlcd_mmap(ctx, offset, prot)
391 void *ctx;
392 off_t offset;
393 int prot;
394 {
395 struct ipaqlcd_softc *sc = (struct ipaqlcd_softc *)ctx;
396
397 if (offset < 0 ||
398 (sc->sc_fbconf.hf_bytes_per_plane +
399 sc->sc_fbconf.hf_offset) < offset)
400 return -1;
401
402 return __BTOP((u_long)bootinfo->fb_addr + offset);
403 }
404