1 /* $NetBSD: ipaq_lcd.c,v 1.17 2008/04/28 20:23:21 martin Exp $ */
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ichiro FUKUHARA (ichiro@ichiro.org).
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: ipaq_lcd.c,v 1.17 2008/04/28 20:23:21 martin Exp $");
35 #define IPAQ_LCD_DEBUG
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
42 #include <sys/device.h>
44 #include <uvm/uvm_extern.h>
46 #include <dev/wscons/wsconsio.h>
48 #include <machine/bootinfo.h>
49 #include <machine/bus.h>
50 #include <machine/intr.h>
51 #include <arm/cpufunc.h>
52 #include <arm/arm32/katelib.h>
54 #include <arm/sa11x0/sa11x0_reg.h>
55 #include <arm/sa11x0/sa11x0_gpioreg.h>
57 #include <hpcarm/dev/ipaq_gpioreg.h>
58 #include <hpcarm/dev/ipaq_saipvar.h>
59 #include <hpcarm/dev/ipaq_lcdreg.h>
60 #include <hpcarm/dev/ipaq_lcdvar.h>
63 #define DPRINTFN(n, x) if (ipaqlcddebug > (n)) aprint_normal x
64 int ipaqlcddebug
= 0xff;
66 #define DPRINTFN(n, x)
68 #define DPRINTF(x) DPRINTFN(0, x)
70 static int ipaqlcd_match(device_t
, cfdata_t
, void *);
71 static void ipaqlcd_attach(device_t
, device_t
, void *);
72 static void ipaqlcd_init(struct ipaqlcd_softc
*);
73 static int ipaqlcd_fbinit(struct ipaqlcd_softc
*);
74 static int ipaqlcd_ioctl(void *, u_long
, void *, int, struct lwp
*);
75 static paddr_t
ipaqlcd_mmap(void *, off_t
, int);
77 #if defined __mips__ || defined __sh__ || defined __arm__
78 #define __BTOP(x) ((paddr_t)(x) >> PGSHIFT)
79 #define __PTOB(x) ((paddr_t)(x) << PGSHIFT)
81 #error "define btop, ptob."
84 CFATTACH_DECL_NEW(ipaqlcd
, sizeof(struct ipaqlcd_softc
),
85 ipaqlcd_match
, ipaqlcd_attach
, NULL
, NULL
);
87 struct hpcfb_accessops ipaqlcd_ha
= {
88 ipaqlcd_ioctl
, ipaqlcd_mmap
90 static int console_flag
= 0;
93 ipaqlcd_match(device_t parent
, cfdata_t match
, void *aux
)
99 ipaqlcd_attach(device_t parent
, device_t self
, void *aux
)
101 struct ipaqlcd_softc
*sc
= device_private(self
);
102 struct hpcfb_attach_args ha
;
103 struct ipaq_softc
*psc
= device_private(parent
);
106 sc
->sc_iot
= psc
->sc_iot
;
113 aprint_normal_dev(self
, "iPAQ internal LCD controller\n");
115 DPRINTF(("framebuffer_baseaddr=%lx\n", (u_long
)bootinfo
->fb_addr
));
117 ha
.ha_console
= console_flag
;
118 ha
.ha_accessops
= &ipaqlcd_ha
;
119 ha
.ha_accessctx
= sc
;
122 ha
.ha_fbconflist
= &sc
->sc_fbconf
;
123 ha
.ha_curdspconf
= 0;
125 ha
.ha_dspconflist
= &sc
->sc_dspconf
;
127 config_found(sc
->sc_dev
, &ha
, hpcfbprint
);
131 ipaqlcd_init(struct ipaqlcd_softc
*sc
)
133 /* Initialization of Extended GPIO */
134 sc
->sc_parent
->ipaq_egpio
|= EGPIO_LCD_INIT
;
135 bus_space_write_2(sc
->sc_iot
, sc
->sc_parent
->sc_egpioh
,
136 0, sc
->sc_parent
->ipaq_egpio
);
138 if (bus_space_map(sc
->sc_iot
, SALCD_BASE
, SALCD_NPORTS
,
140 panic("ipaqlcd_init:Cannot map registers");
142 bootinfo
->fb_addr
= (void *)
143 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, SALCD_BA1
);
146 * Initialize LCD Control Register 0 - 3
147 * must initialize DMA Channel Base Address Register
148 * before enabling LCD(LEN = 1)
150 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
,
151 SALCD_CR1
, IPAQ_LCCR1
);
152 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
,
153 SALCD_CR2
, IPAQ_LCCR2
);
154 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
,
155 SALCD_CR3
, IPAQ_LCCR3
);
156 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
,
157 SALCD_CR0
, IPAQ_LCCR0
);
160 "DMA_BASE= %08x : DMA_CUR = %08x \n"
161 "LCCR0 = %08x : LCCR1 = %08x \n"
162 "LCCR2 = %08x : LCCR3 = %08x",
163 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, SALCD_BA1
),
164 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, SALCD_CA1
),
165 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, SALCD_CR0
),
166 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, SALCD_CR1
),
167 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, SALCD_CR2
),
168 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, SALCD_CR3
)));
173 ipaqlcd_fbinit(struct ipaqlcd_softc
*sc
)
175 struct hpcfb_fbconf
*fb
;
180 memset(fb
, 0, sizeof(*fb
));
182 fb
->hf_conf_index
= 0; /* configuration index */
184 strcpy(fb
->hf_name
, "built-in video");
185 strcpy(fb
->hf_conf_name
, "LCD");
186 /* configuration name */
187 fb
->hf_height
= bootinfo
->fb_height
;
188 fb
->hf_width
= bootinfo
->fb_width
;
190 if (bus_space_map(sc
->sc_iot
, (bus_addr_t
)bootinfo
->fb_addr
,
191 bootinfo
->fb_height
* bootinfo
->fb_line_bytes
,
192 0, &fb
->hf_baseaddr
)) {
193 aprint_normal("unable to map framebuffer\n");
197 fb
->hf_offset
= (u_long
)bootinfo
->fb_addr
-
198 __PTOB(__BTOP(bootinfo
->fb_addr
));
199 /* frame buffer start offset */
200 fb
->hf_bytes_per_line
= bootinfo
->fb_line_bytes
;
202 fb
->hf_bytes_per_plane
= bootinfo
->fb_height
*
203 bootinfo
->fb_line_bytes
;
205 fb
->hf_access_flags
|= HPCFB_ACCESS_BYTE
;
206 fb
->hf_access_flags
|= HPCFB_ACCESS_WORD
;
207 fb
->hf_access_flags
|= HPCFB_ACCESS_DWORD
;
209 switch (bootinfo
->fb_type
) {
214 case BIFB_D2_M2L_3x2
:
215 fb
->hf_access_flags
|= HPCFB_ACCESS_REVERSE
;
217 case BIFB_D2_M2L_0x2
:
218 fb
->hf_class
= HPCFB_CLASS_GRAYSCALE
;
221 case BIFB_D4_M2L_Fx2
:
222 fb
->hf_access_flags
|= HPCFB_ACCESS_REVERSE
;
224 case BIFB_D4_M2L_0x2
:
225 fb
->hf_class
= HPCFB_CLASS_GRAYSCALE
;
232 fb
->hf_offset
= 0x200;
239 fb
->hf_class
= HPCFB_CLASS_RGBCOLOR
;
240 fb
->hf_access_flags
|= HPCFB_ACCESS_STATIC
;
241 fb
->hf_order_flags
= HPCFB_REVORDER_BYTE
;
242 fb
->hf_pack_width
= 16;
243 fb
->hf_pixels_per_pack
= 1;
244 fb
->hf_pixel_width
= 16;
246 fb
->hf_class_data_length
= sizeof(struct hf_rgb_tag
);
247 fb
->hf_u
.hf_rgb
.hf_flags
= 0;
248 /* reserved for future use */
249 fb
->hf_u
.hf_rgb
.hf_red_width
= 5;
250 fb
->hf_u
.hf_rgb
.hf_red_shift
= 11;
251 fb
->hf_u
.hf_rgb
.hf_green_width
= 6;
252 fb
->hf_u
.hf_rgb
.hf_green_shift
= 5;
253 fb
->hf_u
.hf_rgb
.hf_blue_width
= 5;
254 fb
->hf_u
.hf_rgb
.hf_blue_shift
= 0;
255 fb
->hf_u
.hf_rgb
.hf_alpha_width
= 0;
256 fb
->hf_u
.hf_rgb
.hf_alpha_shift
= 0;
259 aprint_normal("unknown type (=%d).\n",
269 ipaqlcd_ioctl(void *v
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
271 struct ipaqlcd_softc
*sc
= (struct ipaqlcd_softc
*)v
;
272 struct hpcfb_fbconf
*fbconf
;
273 struct hpcfb_dspconf
*dspconf
;
274 struct wsdisplay_cmap
*cmap
;
275 struct wsdisplay_param
*dispparam
;
278 case WSDISPLAYIO_GETCMAP
:
279 cmap
= (struct wsdisplay_cmap
*)data
;
281 if (sc
->sc_fbconf
.hf_class
!= HPCFB_CLASS_INDEXCOLOR
||
282 sc
->sc_fbconf
.hf_pack_width
!= 8 ||
283 256 <= cmap
->index
||
284 256 < (cmap
->index
+ cmap
->count
))
287 case WSDISPLAYIO_PUTCMAP
:
289 case WSDISPLAYIO_GETPARAM
:
290 dispparam
= (struct wsdisplay_param
*)data
;
291 switch (dispparam
->param
) {
292 case WSDISPLAYIO_PARAM_BACKLIGHT
:
293 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BACKLIGHT\n"));
295 case WSDISPLAYIO_PARAM_CONTRAST
:
296 DPRINTF(("ipaqlcd_ioctl: GETPARAM:CONTRAST\n"));
298 case WSDISPLAYIO_PARAM_BRIGHTNESS
:
299 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BRIGHTNESS\n"));
305 case WSDISPLAYIO_SETPARAM
:
306 dispparam
= (struct wsdisplay_param
*)data
;
307 switch (dispparam
->param
) {
308 case WSDISPLAYIO_PARAM_BACKLIGHT
:
309 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BACKLIGHT\n"));
311 case WSDISPLAYIO_PARAM_CONTRAST
:
312 DPRINTF(("ipaqlcd_ioctl: GETPARAM:CONTRAST\n"));
314 case WSDISPLAYIO_PARAM_BRIGHTNESS
:
315 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BRIGHTNESS\n"));
323 fbconf
= (struct hpcfb_fbconf
*)data
;
324 if (fbconf
->hf_conf_index
!= 0 &&
325 fbconf
->hf_conf_index
!= HPCFB_CURRENT_CONFIG
) {
328 *fbconf
= sc
->sc_fbconf
; /* structure assignment */
331 fbconf
= (struct hpcfb_fbconf
*)data
;
332 if (fbconf
->hf_conf_index
!= 0 &&
333 fbconf
->hf_conf_index
!= HPCFB_CURRENT_CONFIG
) {
337 * nothing to do because we have only one configuration
340 case HPCFBIO_GDSPCONF
:
341 dspconf
= (struct hpcfb_dspconf
*)data
;
342 if ((dspconf
->hd_unit_index
!= 0 &&
343 dspconf
->hd_unit_index
!= HPCFB_CURRENT_UNIT
) ||
344 (dspconf
->hd_conf_index
!= 0 &&
345 dspconf
->hd_conf_index
!= HPCFB_CURRENT_CONFIG
)) {
348 *dspconf
= sc
->sc_dspconf
; /* structure assignment */
350 case HPCFBIO_SDSPCONF
:
351 dspconf
= (struct hpcfb_dspconf
*)data
;
352 if ((dspconf
->hd_unit_index
!= 0 &&
353 dspconf
->hd_unit_index
!= HPCFB_CURRENT_UNIT
) ||
354 (dspconf
->hd_conf_index
!= 0 &&
355 dspconf
->hd_conf_index
!= HPCFB_CURRENT_CONFIG
)) {
360 * because we have only one unit and one configuration
368 return (EPASSTHROUGH
);
372 ipaqlcd_mmap(void *ctx
, off_t offset
, int prot
)
374 struct ipaqlcd_softc
*sc
= (struct ipaqlcd_softc
*)ctx
;
377 (sc
->sc_fbconf
.hf_bytes_per_plane
+
378 sc
->sc_fbconf
.hf_offset
) < offset
)
381 return __BTOP((u_long
)bootinfo
->fb_addr
+ offset
);