ipaq_lcd.c revision 1.16 1 /* $NetBSD: ipaq_lcd.c,v 1.16 2007/03/04 05:59:52 christos 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.16 2007/03/04 05:59:52 christos 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 <arm/sa11x0/sa11x0_reg.h>
62 #include <arm/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, void *, int, struct lwp *);
82 static paddr_t ipaqlcd_mmap(void *, off_t, 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(struct device *parent, struct cfdata *match, void *aux)
101 {
102 return (1);
103 }
104
105 void
106 ipaqlcd_attach(struct device *parent, struct device *self, void *aux)
107 {
108 struct ipaqlcd_softc *sc = (struct ipaqlcd_softc*)self;
109 struct hpcfb_attach_args ha;
110 struct ipaq_softc *psc = (struct ipaq_softc *)parent;
111
112 sc->sc_iot = psc->sc_iot;
113 sc->sc_parent = (struct ipaq_softc *)parent;
114
115 ipaqlcd_init(sc);
116 ipaqlcd_fbinit(sc);
117
118 printf("\n");
119 printf("%s: iPAQ internal LCD controller\n", sc->sc_dev.dv_xname);
120
121 DPRINTF(("framebuffer_baseaddr=%lx\n", (u_long)bootinfo->fb_addr));
122
123 ha.ha_console = console_flag;
124 ha.ha_accessops = &ipaqlcd_ha;
125 ha.ha_accessctx = sc;
126 ha.ha_curfbconf = 0;
127 ha.ha_nfbconf = 1;
128 ha.ha_fbconflist = &sc->sc_fbconf;
129 ha.ha_curdspconf = 0;
130 ha.ha_ndspconf = 1;
131 ha.ha_dspconflist = &sc->sc_dspconf;
132
133 config_found(&sc->sc_dev, &ha, hpcfbprint);
134 }
135
136 void
137 ipaqlcd_init(struct ipaqlcd_softc *sc)
138 {
139 /* Initialization of Extended GPIO */
140 sc->sc_parent->ipaq_egpio |= EGPIO_LCD_INIT;
141 bus_space_write_2(sc->sc_iot, sc->sc_parent->sc_egpioh,
142 0, sc->sc_parent->ipaq_egpio);
143
144 if (bus_space_map(sc->sc_iot, SALCD_BASE, SALCD_NPORTS,
145 0, &sc->sc_ioh))
146 panic("ipaqlcd_init:Cannot map registers");
147
148 bootinfo->fb_addr = (void *)
149 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_BA1);
150
151 /*
152 * Initialize LCD Control Register 0 - 3
153 * must initialize DMA Channel Base Address Register
154 * before enabling LCD(LEN = 1)
155 */
156 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
157 SALCD_CR1, IPAQ_LCCR1);
158 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
159 SALCD_CR2, IPAQ_LCCR2);
160 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
161 SALCD_CR3, IPAQ_LCCR3);
162 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
163 SALCD_CR0, IPAQ_LCCR0);
164
165 DPRINTF(("\n"
166 "DMA_BASE= %08x : DMA_CUR = %08x \n"
167 "LCCR0 = %08x : LCCR1 = %08x \n"
168 "LCCR2 = %08x : LCCR3 = %08x",
169 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_BA1),
170 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CA1),
171 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR0),
172 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR1),
173 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR2),
174 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR3)));
175
176 }
177
178 int
179 ipaqlcd_fbinit(struct ipaqlcd_softc *sc)
180 {
181 struct hpcfb_fbconf *fb;
182
183 fb = &sc->sc_fbconf;
184
185 /* Initialize fb */
186 memset(fb, 0, sizeof(*fb));
187
188 fb->hf_conf_index = 0; /* configuration index */
189 fb->hf_nconfs = 1;
190 strcpy(fb->hf_name, "built-in video");
191 strcpy(fb->hf_conf_name, "LCD");
192 /* configuration name */
193 fb->hf_height = bootinfo->fb_height;
194 fb->hf_width = bootinfo->fb_width;
195
196 if (bus_space_map(sc->sc_iot, (bus_addr_t)bootinfo->fb_addr,
197 bootinfo->fb_height * bootinfo->fb_line_bytes,
198 0, &fb->hf_baseaddr)) {
199 printf("unable to map framebuffer\n");
200 return (-1);
201 }
202
203 fb->hf_offset = (u_long)bootinfo->fb_addr -
204 __PTOB(__BTOP(bootinfo->fb_addr));
205 /* frame buffer start offset */
206 fb->hf_bytes_per_line = bootinfo->fb_line_bytes;
207 fb->hf_nplanes = 1;
208 fb->hf_bytes_per_plane = bootinfo->fb_height *
209 bootinfo->fb_line_bytes;
210
211 fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
212 fb->hf_access_flags |= HPCFB_ACCESS_WORD;
213 fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
214
215 switch (bootinfo->fb_type) {
216 /*
217 * gray scale
218 */
219 case BIFB_D2_M2L_3:
220 case BIFB_D2_M2L_3x2:
221 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
222 case BIFB_D2_M2L_0:
223 case BIFB_D2_M2L_0x2:
224 fb->hf_class = HPCFB_CLASS_GRAYSCALE;
225 break;
226 case BIFB_D4_M2L_F:
227 case BIFB_D4_M2L_Fx2:
228 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
229 case BIFB_D4_M2L_0:
230 case BIFB_D4_M2L_0x2:
231 fb->hf_class = HPCFB_CLASS_GRAYSCALE;
232 break;
233 /*
234 * indexed color
235 */
236 case BIFB_D8_FF:
237 case BIFB_D8_00:
238 fb->hf_offset = 0x200;
239 break;
240 /*
241 * RGB color
242 */
243 case BIFB_D16_FFFF:
244 case BIFB_D16_0000:
245 fb->hf_class = HPCFB_CLASS_RGBCOLOR;
246 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
247 fb->hf_order_flags = HPCFB_REVORDER_BYTE;
248 fb->hf_pack_width = 16;
249 fb->hf_pixels_per_pack = 1;
250 fb->hf_pixel_width = 16;
251
252 fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
253 fb->hf_u.hf_rgb.hf_flags = 0;
254 /* reserved for future use */
255 fb->hf_u.hf_rgb.hf_red_width = 5;
256 fb->hf_u.hf_rgb.hf_red_shift = 11;
257 fb->hf_u.hf_rgb.hf_green_width = 6;
258 fb->hf_u.hf_rgb.hf_green_shift = 5;
259 fb->hf_u.hf_rgb.hf_blue_width = 5;
260 fb->hf_u.hf_rgb.hf_blue_shift = 0;
261 fb->hf_u.hf_rgb.hf_alpha_width = 0;
262 fb->hf_u.hf_rgb.hf_alpha_shift = 0;
263 break;
264 default :
265 printf("unknown type (=%d).\n", bootinfo->fb_type);
266 return (-1);
267 break;
268 }
269
270 return(0);
271 }
272
273 int
274 ipaqlcd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
275 {
276 struct ipaqlcd_softc *sc = (struct ipaqlcd_softc *)v;
277 struct hpcfb_fbconf *fbconf;
278 struct hpcfb_dspconf *dspconf;
279 struct wsdisplay_cmap *cmap;
280 struct wsdisplay_param *dispparam;
281
282 switch (cmd) {
283 case WSDISPLAYIO_GETCMAP:
284 cmap = (struct wsdisplay_cmap*)data;
285
286 if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
287 sc->sc_fbconf.hf_pack_width != 8 ||
288 256 <= cmap->index ||
289 256 < (cmap->index + cmap->count))
290 return (EINVAL);
291 return (0);
292 case WSDISPLAYIO_PUTCMAP:
293 return (EINVAL);
294 case WSDISPLAYIO_GETPARAM:
295 dispparam = (struct wsdisplay_param*)data;
296 switch (dispparam->param) {
297 case WSDISPLAYIO_PARAM_BACKLIGHT:
298 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BACKLIGHT\n"));
299 return (EINVAL);
300 case WSDISPLAYIO_PARAM_CONTRAST:
301 DPRINTF(("ipaqlcd_ioctl: GETPARAM:CONTRAST\n"));
302 return (EINVAL);
303 case WSDISPLAYIO_PARAM_BRIGHTNESS:
304 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BRIGHTNESS\n"));
305 return (EINVAL);
306 default:
307 return (EINVAL);
308 }
309 return (0);
310 case WSDISPLAYIO_SETPARAM:
311 dispparam = (struct wsdisplay_param*)data;
312 switch (dispparam->param) {
313 case WSDISPLAYIO_PARAM_BACKLIGHT:
314 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BACKLIGHT\n"));
315 return (EINVAL);
316 case WSDISPLAYIO_PARAM_CONTRAST:
317 DPRINTF(("ipaqlcd_ioctl: GETPARAM:CONTRAST\n"));
318 return (EINVAL);
319 case WSDISPLAYIO_PARAM_BRIGHTNESS:
320 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BRIGHTNESS\n"));
321 return (EINVAL);
322 default:
323 return (EINVAL);
324 }
325 return (0);
326
327 case HPCFBIO_GCONF:
328 fbconf = (struct hpcfb_fbconf *)data;
329 if (fbconf->hf_conf_index != 0 &&
330 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
331 return (EINVAL);
332 }
333 *fbconf = sc->sc_fbconf; /* structure assignment */
334 return (0);
335 case HPCFBIO_SCONF:
336 fbconf = (struct hpcfb_fbconf *)data;
337 if (fbconf->hf_conf_index != 0 &&
338 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
339 return (EINVAL);
340 }
341 /*
342 * nothing to do because we have only one configuration
343 */
344 return (0);
345 case HPCFBIO_GDSPCONF:
346 dspconf = (struct hpcfb_dspconf *)data;
347 if ((dspconf->hd_unit_index != 0 &&
348 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
349 (dspconf->hd_conf_index != 0 &&
350 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
351 return (EINVAL);
352 }
353 *dspconf = sc->sc_dspconf; /* structure assignment */
354 return (0);
355 case HPCFBIO_SDSPCONF:
356 dspconf = (struct hpcfb_dspconf *)data;
357 if ((dspconf->hd_unit_index != 0 &&
358 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
359 (dspconf->hd_conf_index != 0 &&
360 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
361 return (EINVAL);
362 }
363 /*
364 * nothing to do
365 * because we have only one unit and one configuration
366 */
367 return (0);
368
369 case HPCFBIO_GOP:
370 case HPCFBIO_SOP:
371 return (EINVAL);
372 }
373 return (EPASSTHROUGH);
374 }
375
376 paddr_t
377 ipaqlcd_mmap(void *ctx, off_t offset, int prot)
378 {
379 struct ipaqlcd_softc *sc = (struct ipaqlcd_softc *)ctx;
380
381 if (offset < 0 ||
382 (sc->sc_fbconf.hf_bytes_per_plane +
383 sc->sc_fbconf.hf_offset) < offset)
384 return -1;
385
386 return __BTOP((u_long)bootinfo->fb_addr + offset);
387 }
388