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@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