1 /* $NetBSD: netwalker_lcd.c,v 1.4 2014/07/25 08:10:33 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 2011, 2012 Genetec corp. All rights reserved. 5 * Written by Hashimoto Kenichi for Genetec corp. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: netwalker_lcd.c,v 1.4 2014/07/25 08:10:33 dholland Exp $"); 31 32 #include "opt_imx51_ipuv3.h" 33 #include "opt_netwalker_lcd.h" 34 35 #include "wsdisplay.h" 36 #include "ioconf.h" 37 #include "netwalker_backlight.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/conf.h> 42 #include <sys/uio.h> 43 #include <sys/malloc.h> 44 #include <sys/device.h> 45 #include <sys/pmf.h> 46 47 #include <dev/cons.h> 48 #include <dev/wscons/wsconsio.h> 49 #include <dev/wscons/wsdisplayvar.h> 50 #include <dev/wscons/wscons_callbacks.h> 51 52 #include <sys/bus.h> 53 #include <arm/imx/imx51var.h> 54 #include <arm/imx/imx51reg.h> 55 #include <arm/imx/imx51_ipuv3var.h> 56 #include <arm/imx/imx51_ipuv3reg.h> 57 #include <arm/imx/imxgpiovar.h> 58 59 #include <evbarm/netwalker/netwalker_backlightvar.h> 60 61 int lcd_match(device_t, cfdata_t, void *); 62 void lcd_attach(device_t, device_t, void *); 63 64 void netwalker_cnattach(void); 65 66 #if NWSDISPLAY > 0 67 static int netwalker_lcd_ioctl(void *, void *, u_long, void *, int, 68 struct lwp *); 69 static int netwalker_lcd_show_screen(void *, void *, int, 70 void (*)(void *, int, int), void *); 71 72 bool netwalker_lcd_console = 0; 73 74 /* 75 * wsdisplay glue 76 */ 77 static struct imx51_wsscreen_descr netwalker_lcd_stdscreen = { 78 .c = { 79 .name = "std", 80 .ncols = 0, 81 .nrows = 0, 82 .textops = NULL, 83 .fontwidth = 8, 84 .fontheight = 16, 85 .capabilities = WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 86 .modecookie = NULL 87 }, 88 .depth = 16, /* bits per pixel */ 89 .flags = RI_CENTER | RI_FULLCLEAR 90 }; 91 92 static const struct wsscreen_descr *netwalker_lcd_scr_descr[] = { 93 &netwalker_lcd_stdscreen.c, 94 }; 95 96 const struct wsscreen_list netwalker_lcd_screen_list = { 97 sizeof netwalker_lcd_scr_descr / sizeof netwalker_lcd_scr_descr[0], 98 netwalker_lcd_scr_descr 99 }; 100 101 struct wsdisplay_accessops netwalker_lcd_accessops = { 102 .ioctl = netwalker_lcd_ioctl, 103 .mmap = imx51_ipuv3_mmap, 104 .alloc_screen = imx51_ipuv3_alloc_screen, 105 .free_screen = imx51_ipuv3_free_screen, 106 .show_screen = netwalker_lcd_show_screen, 107 .load_font = NULL, 108 .pollc = NULL, 109 .scroll = NULL 110 }; 111 #else 112 #ifdef LCD_DEBUG 113 static void draw_test_pattern(struct imx51_ipuv3_softc *, 114 struct imx51_ipuv3_screen *); 115 #endif 116 117 /* 118 * Interface to LCD framebuffer without wscons 119 */ 120 extern struct cfdriver ipu_cd; 121 122 dev_type_open(lcdopen); 123 dev_type_close(lcdclose); 124 dev_type_ioctl(lcdioctl); 125 dev_type_mmap(lcdmmap); 126 const struct cdevsw ipu_cdevsw = { 127 .d_open = lcdopen, 128 .d_close = lcdclose, 129 .d_read = noread, 130 .d_write = nowrite, 131 .d_ioctl = lcdioctl, 132 .d_stop = nostop, 133 .d_tty = notty, 134 .d_poll = nopoll, 135 .d_mmap = lcdmmap, 136 .d_kqfilter = nokqfilter, 137 .d_discard = nodiscard, 138 .d_flag = D_TTY 139 }; 140 141 #endif 142 143 CFATTACH_DECL_NEW(lcd_netwalker, sizeof (struct imx51_ipuv3_softc), 144 lcd_match, lcd_attach, NULL, NULL); 145 146 int 147 lcd_match( device_t parent, cfdata_t cf, void *aux ) 148 { 149 return 1; 150 } 151 152 /* Sharp's LCD */ 153 static const struct lcd_panel_geometry sharp_panel = 154 { 155 .panel_width = 1024, /* Width */ 156 .panel_height = 600, /* Height */ 157 158 .pixel_clk = 30076000, 159 160 .hsync_width = 8, 161 .left = 20, 162 .right = 20, 163 164 .vsync_width = 4, 165 .upper = 2, 166 .lower = 2, 167 168 .panel_info = 0, 169 }; 170 171 void lcd_attach( device_t parent, device_t self, void *aux ) 172 { 173 struct imx51_ipuv3_softc *sc = device_private(self); 174 struct axi_attach_args *axia = aux; 175 bus_space_tag_t iot = axia->aa_iot; 176 177 sc->dev = self; 178 179 #if defined(IMXIPUCONSOLE) 180 netwalker_lcd_console = 1; 181 #endif 182 #if (NWSDISPLAY > 0) 183 netwalker_cnattach(); 184 #endif 185 186 /* XXX move this to imx51_ipuv3.c */ 187 { 188 bus_space_handle_t mipi_ioh; 189 uint32_t reg; 190 191 if (bus_space_map(iot, 0x83fdc000, 0x1000, 0, &mipi_ioh)) 192 aprint_error_dev(self, "can't map MIPI HSC"); 193 else { 194 bus_space_write_4(iot, mipi_ioh, 0x000, 0xf00); 195 196 reg = bus_space_read_4(iot, mipi_ioh, 0x800); 197 bus_space_write_4(iot, mipi_ioh, 0x800, reg | 0x0ff); 198 199 reg = bus_space_read_4(iot, mipi_ioh, 0x800); 200 bus_space_write_4(iot, mipi_ioh, 0x800, reg | 0x10000); 201 } 202 } 203 204 /* LCD power on */ 205 gpio_set_direction(GPIO_NO(4, 9), GPIO_DIR_OUT); 206 gpio_set_direction(GPIO_NO(4, 10), GPIO_DIR_OUT); 207 gpio_set_direction(GPIO_NO(3, 3), GPIO_DIR_OUT); 208 209 gpio_data_write(GPIO_NO(3, 3), 1); 210 gpio_data_write(GPIO_NO(4, 9), 1); 211 delay(180 * 1000); 212 gpio_data_write(GPIO_NO(4, 10), 1); 213 214 gpio_set_direction(GPIO_NO(2, 13), GPIO_DIR_OUT); 215 gpio_data_write(GPIO_NO(2, 13), 1); 216 217 imx51_ipuv3_attach_sub(sc, aux, &sharp_panel); 218 219 #if NWSDISPLAY == 0 220 struct imx51_ipuv3_screen *screen; 221 int error; 222 223 error = imx51_ipuv3_new_screen(sc, 16, &screen); 224 #ifdef LCD_DEBUG 225 draw_test_pattern(sc, screen); 226 #endif 227 if (error == 0) { 228 sc->active = screen; 229 imx51_ipuv3_start_dma(sc, screen); 230 } 231 #else 232 struct wsemuldisplaydev_attach_args aa; 233 234 #if defined(IMXIPUCONSOLE) 235 aa.console = true; 236 #else 237 aa.console = false; 238 #endif 239 aa.scrdata = &netwalker_lcd_screen_list; 240 aa.accessops = &netwalker_lcd_accessops; 241 aa.accesscookie = &sc->vd; 242 243 (void) config_found(sc->dev, &aa, wsemuldisplaydevprint); 244 #endif 245 } 246 247 #if NWSDISPLAY > 0 248 void 249 netwalker_cnattach(void) 250 { 251 imx51_ipuv3_cnattach(netwalker_lcd_console, &netwalker_lcd_stdscreen, 252 &netwalker_lcd_accessops, &sharp_panel); 253 return; 254 } 255 256 /* 257 * wsdisplay accessops overrides 258 */ 259 static int 260 netwalker_lcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 261 { 262 int res = EINVAL; 263 264 switch (cmd) { 265 #if NNETWALKER_BACKLIGHT > 0 266 case WSDISPLAYIO_GETPARAM: 267 case WSDISPLAYIO_SETPARAM: 268 res = netwalker_lcd_param_ioctl(cmd, (struct wsdisplay_param *)data); 269 break; 270 #endif 271 } 272 273 if (res == EINVAL) 274 res = imx51_ipuv3_ioctl(v, vs, cmd, data, flag, l); 275 return res; 276 } 277 278 static int 279 netwalker_lcd_show_screen(void *v, void *cookie, int waitok, 280 void (*cb_func)(void *, int, int), void *cb_arg) 281 { 282 int error; 283 284 error = imx51_ipuv3_show_screen(v, cookie, waitok, cb_func, cb_arg); 285 if (error) 286 return (error); 287 288 return 0; 289 } 290 #else 291 292 int 293 lcdopen(dev_t dev, int oflags, int devtype, struct lwp *l) 294 { 295 return 0; 296 } 297 298 int 299 lcdclose(dev_t dev, int fflag, int devtype, struct lwp *l) 300 { 301 return 0; 302 } 303 304 paddr_t 305 lcdmmap(dev_t dev, off_t offset, int size) 306 { 307 struct imx51_ipuv3_softc *sc = 308 device_lookup_private(&ipu_cd, minor(dev)); 309 struct imx51_ipuv3_screen *scr = sc->active; 310 311 return bus_dmamem_mmap(sc->dma_tag, scr->segs, scr->nsegs, 312 offset, 0, BUS_DMA_WAITOK|BUS_DMA_COHERENT); 313 } 314 315 int 316 lcdioctl(dev_t dev, u_long cmd, void *data, 317 int fflag, struct lwp *l) 318 { 319 return EOPNOTSUPP; 320 } 321 322 #ifdef LCD_DEBUG 323 static void 324 draw_test_pattern(struct imx51_ipuv3_softc *sc, 325 struct imx51_ipuv3_screen *scr) 326 { 327 int x, y; 328 uint16_t color, *line; 329 char *buf = (char *)(scr->buf_va); 330 331 printf("%s: buf_va %p, size 0x%x\n", __func__, buf, 332 (uint)scr->buf_size); 333 printf("%s: panel %d x %d\n", __func__, 334 sc->geometry->panel_width, 335 sc->geometry->panel_height); 336 #define rgb(r,g,b) (((r)<<11) | ((g)<<5) | (b)) 337 338 for (y=0; y < sc->geometry->panel_height; ++y) { 339 line = (uint16_t *)(buf + scr->stride * y); 340 341 for (x=0; x < sc->geometry->panel_width; ++x) { 342 switch (((x/30) + (y/10)) % 8) { 343 default: 344 case 0: color = rgb(0x00, 0x00, 0x00); break; 345 case 1: color = rgb(0x00, 0x00, 0x1f); break; 346 case 2: color = rgb(0x00, 0x3f, 0x00); break; 347 case 3: color = rgb(0x00, 0x3f, 0x1f); break; 348 case 4: color = rgb(0x1f, 0x00, 0x00); break; 349 case 5: color = rgb(0x1f, 0x00, 0x1f); break; 350 case 6: color = rgb(0x1f, 0x3f, 0x00); break; 351 case 7: color = rgb(0x1f, 0x3f, 0x1f); break; 352 } 353 354 line[x] = color; 355 } 356 } 357 358 for (x=0; x < MIN(sc->geometry->panel_height, 359 sc->geometry->panel_width); ++x) { 360 line = (uint16_t *)(buf + scr->stride * x); 361 line[x] = rgb(0x1f, 0x3f, 0x1f); 362 } 363 } 364 #endif 365 366 #endif /* NWSDISPLAY > 0 */ 367 368 369