1 /*        $NetBSD: sed_saip.c,v 1.29 2022/05/28 10:36:22 andvar Exp $ */
2 
3 /*-
4  * Copyright (c) 1999-2001
5  *         Shin Takemura and PocketBSD Project. All rights reserved.
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  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *        This product includes software developed by the PocketBSD project
18  *        and its contributors.
19  * 4. Neither the name of the project nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: sed_saip.c,v 1.29 2022/05/28 10:36:22 andvar Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <sys/reboot.h>
45 #include <sys/bus.h>
46 
47 #include <machine/bootinfo.h>
48 #include <machine/config_hook.h>
49 #include <machine/platid.h>
50 #include <machine/platid_mask.h>
51 
52 #include <dev/wscons/wsconsio.h>
53 #include <dev/wscons/wsdisplayvar.h>
54 
55 #include <dev/rasops/rasops.h>
56 
57 #include <dev/hpc/hpcfbvar.h>
58 #include <dev/hpc/hpcfbio.h>
59 #include <dev/hpc/hpccmapvar.h>
60 
61 #include <hpcarm/dev/sed1356var.h>
62 
63 #ifdef SED_DEBUG
64 #define VPRINTF(arg)          do { if (bootverbose) aprint_normal arg; } while (0)
65 #else
66 #define VPRINTF(arg)          /* nothing */
67 #endif
68 
69 /*
70  * Function prototypes.
71  */
72 static int          sed1356_match(device_t, cfdata_t, void *);
73 static void         sed1356_attach(device_t, device_t, void *);
74 static int          sed1356_ioctl(void *, u_long, void *, int, struct lwp *);
75 static paddr_t      sed1356_mmap(void *, off_t, int);
76 
77 static int          sed1356_init(struct hpcfb_fbconf *);
78 static void         sed1356_power(int, void *);
79 static void         sed1356_update_powerstate(struct sed1356_softc *, int);
80 static void         sed1356_init_backlight(struct sed1356_softc *, int);
81 static void         sed1356_set_brightness(struct sed1356_softc *, int);
82 static void         sed1356_set_contrast(struct sed1356_softc *, 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 /*
92  * External functions/variables.
93  */
94 extern struct cfdriver sed_cd;
95 extern struct bus_space sa11x0_bs_tag;
96 extern int j720lcd_power(void *, int, long, void *);   /* XXX */
97 
98 /*
99  * Static variables.
100  */
101 CFATTACH_DECL_NEW(sed, sizeof(struct sed1356_softc),
102     sed1356_match, sed1356_attach, NULL, NULL);
103 struct hpcfb_accessops sed1356_ha = {
104           sed1356_ioctl, sed1356_mmap
105 };
106 
107 static int attach_flag = 0;
108 
109 /*
110  * Function bodies.
111  */
112 static int
sed1356_match(device_t parent,cfdata_t match,void * aux)113 sed1356_match(device_t parent, cfdata_t match, void *aux)
114 {
115 
116           /* XXX check version register */
117           return 1;
118 }
119 
120 static void
sed1356_attach(device_t parent,device_t self,void * aux)121 sed1356_attach(device_t parent, device_t self, void *aux)
122 {
123           struct sed1356_softc *sc = device_private(self);
124           struct hpcfb_attach_args ha;
125           int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1;
126 
127           if (attach_flag) {
128                     panic("%s(%d): sed1356 attached twice", __FILE__, __LINE__);
129           }
130           attach_flag = 1;
131 
132           if (sed1356_init(&sc->sc_fbconf) != 0) {
133                     /* just return so that hpcfb will not be attached */
134                     return;
135           }
136           aprint_normal("\n");
137 
138           sc->sc_dev = self;
139           sc->sc_iot = &sa11x0_bs_tag;
140           sc->sc_parent = device_private(parent);
141           if (bus_space_map(sc->sc_iot, (bus_addr_t)bootinfo->fb_addr & ~0x3fffff,
142               0x200, 0, &sc->sc_regh)) {
143                     aprint_normal_dev(self, "unable to map register\n");
144                     return;
145           }
146 
147           aprint_normal_dev(self, "Epson SED1356");
148           if (console) {
149                     aprint_normal(", console");
150           }
151           aprint_normal("\n");
152           aprint_normal_dev(self, "framebuffer address: 0x%08lx\n",
153                                 (u_long)bootinfo->fb_addr);
154 
155           /* Add a suspend hook to power saving */
156           sc->sc_powerstate = 0;
157           sc->sc_powerhook = powerhook_establish(device_xname(self),
158               sed1356_power, sc);
159           if (sc->sc_powerhook == NULL)
160                     aprint_normal_dev(self, "WARNING: unable to establish power hook\n");
161 
162           /* Initialize backlight brightness and lcd contrast */
163           sc->sc_lcd_inited = 0;
164           sed1356_init_brightness(sc, 1);
165           sed1356_init_contrast(sc, 1);
166           sed1356_init_backlight(sc, 1);
167 
168           if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0)
169                     panic("sed1356_attach: cannot init fb console");
170 
171           ha.ha_console = console;
172           ha.ha_accessops = &sed1356_ha;
173           ha.ha_accessctx = sc;
174           ha.ha_curfbconf = 0;
175           ha.ha_nfbconf = 1;
176           ha.ha_fbconflist = &sc->sc_fbconf;
177           ha.ha_curdspconf = 0;
178           ha.ha_ndspconf = 1;
179           ha.ha_dspconflist = &sc->sc_dspconf;
180 
181           /* XXX */
182           if (platid_match(&platid, &platid_mask_MACH_HP_JORNADA_7XX)) {
183                     config_hook(CONFIG_HOOK_POWERCONTROL,
184                                   CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
185                                   CONFIG_HOOK_SHARE, j720lcd_power, sc);
186           }
187 
188           config_found(self, &ha, hpcfbprint, CFARGS_NONE);
189 }
190 
191 static int
sed1356_init(struct hpcfb_fbconf * fb)192 sed1356_init(struct hpcfb_fbconf *fb)
193 {
194           /*
195            * get fb settings from bootinfo
196            */
197           if (bootinfo == NULL ||
198               bootinfo->fb_addr == 0 ||
199               bootinfo->fb_line_bytes == 0 ||
200               bootinfo->fb_width == 0 ||
201               bootinfo->fb_height == 0) {
202                     aprint_normal("no frame buffer information.\n");
203                     return -1;
204           }
205 
206           /* zero fill */
207           memset(fb, 0, sizeof(*fb));
208 
209           fb->hf_conf_index   = 0;      /* configuration index                  */
210           fb->hf_nconfs                 = 1;      /* how many configurations    */
211           strcpy(fb->hf_name, "built-in video");
212                                                   /* frame buffer name                    */
213           strcpy(fb->hf_conf_name, "default");
214                                                   /* configuration name                   */
215           fb->hf_height                 = bootinfo->fb_height;
216           fb->hf_width                  = bootinfo->fb_width;
217 
218           if (bus_space_map(&sa11x0_bs_tag, (bus_addr_t)bootinfo->fb_addr,
219                                  bootinfo->fb_height * bootinfo->fb_line_bytes,
220                                  0, &fb->hf_baseaddr)) {
221                     aprint_normal("unable to map framebuffer\n");
222                     return -1;
223           }
224           fb->hf_offset                 = (u_long)bootinfo->fb_addr -
225                                               __PTOB(__BTOP(bootinfo->fb_addr));
226                                                   /* frame buffer start offset            */
227           fb->hf_bytes_per_line         = bootinfo->fb_line_bytes;
228           fb->hf_nplanes                = 1;
229           fb->hf_bytes_per_plane        = bootinfo->fb_height *
230                                                   bootinfo->fb_line_bytes;
231 
232           fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
233           fb->hf_access_flags |= HPCFB_ACCESS_WORD;
234           fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
235 
236           switch (bootinfo->fb_type) {
237                     /*
238                      * gray scale
239                      */
240           case BIFB_D4_M2L_F:
241           case BIFB_D4_M2L_Fx2:
242                     fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
243                     /* fall through */
244           case BIFB_D4_M2L_0:
245           case BIFB_D4_M2L_0x2:
246                     fb->hf_class = HPCFB_CLASS_GRAYSCALE;
247                     fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
248                     fb->hf_pack_width = 8;
249                     fb->hf_pixels_per_pack = 2;
250                     fb->hf_pixel_width = 4;
251                     fb->hf_class_data_length = sizeof(struct hf_gray_tag);
252                     fb->hf_u.hf_gray.hf_flags = 0;          /* reserved for future use */
253                     break;
254 
255                     /*
256                      * indexed color
257                      */
258           case BIFB_D8_FF:
259                     fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
260                     /* fall through */
261           case BIFB_D8_00:
262                     fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
263                     fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
264                     fb->hf_pack_width = 8;
265                     fb->hf_pixels_per_pack = 1;
266                     fb->hf_pixel_width = 8;
267                     fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
268                     fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
269                     break;
270 
271                     /*
272                      * RGB color
273                      */
274           case BIFB_D16_FFFF:
275                     fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
276                     /* fall through */
277           case BIFB_D16_0000:
278                     fb->hf_class = HPCFB_CLASS_RGBCOLOR;
279                     fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
280                     fb->hf_order_flags = HPCFB_REVORDER_BYTE;
281                     fb->hf_pack_width = 16;
282                     fb->hf_pixels_per_pack = 1;
283                     fb->hf_pixel_width = 16;
284 
285                     fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
286                     fb->hf_u.hf_rgb.hf_flags = 0; /* reserved for future use */
287 
288                     fb->hf_u.hf_rgb.hf_red_width = 5;
289                     fb->hf_u.hf_rgb.hf_red_shift = 11;
290                     fb->hf_u.hf_rgb.hf_green_width = 6;
291                     fb->hf_u.hf_rgb.hf_green_shift = 5;
292                     fb->hf_u.hf_rgb.hf_blue_width = 5;
293                     fb->hf_u.hf_rgb.hf_blue_shift = 0;
294                     fb->hf_u.hf_rgb.hf_alpha_width = 0;
295                     fb->hf_u.hf_rgb.hf_alpha_shift = 0;
296                     break;
297 
298           default:
299                     aprint_normal("unsupported type %d.\n", bootinfo->fb_type);
300                     return -1;
301           }
302 
303           return 0; /* no error */
304 }
305 
306 static void
sed1356_power(int why,void * arg)307 sed1356_power(int why, void *arg)
308 {
309           struct sed1356_softc *sc = arg;
310 
311           switch (why) {
312           case PWR_SUSPEND:
313           case PWR_STANDBY:
314                     sc->sc_powerstate |= PWRSTAT_SUSPEND;
315                     sed1356_update_powerstate(sc, PWRSTAT_ALL);
316                     break;
317           case PWR_RESUME:
318                     sc->sc_powerstate &= ~PWRSTAT_SUSPEND;
319                     sed1356_update_powerstate(sc, PWRSTAT_ALL);
320                     break;
321           }
322 }
323 
324 static void
sed1356_update_powerstate(struct sed1356_softc * sc,int updates)325 sed1356_update_powerstate(struct sed1356_softc *sc, int updates)
326 {
327           if (updates & PWRSTAT_LCD)
328                     config_hook_call(CONFIG_HOOK_POWERCONTROL,
329                         CONFIG_HOOK_POWERCONTROL_LCD,
330                         (void *)!(sc->sc_powerstate &
331                                         (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)));
332 
333           if (updates & PWRSTAT_BACKLIGHT)
334                     config_hook_call(CONFIG_HOOK_POWERCONTROL,
335                         CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
336                         (void *)(!(sc->sc_powerstate &
337                                         (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)) &&
338                                    (sc->sc_powerstate & PWRSTAT_BACKLIGHT)));
339 }
340 
341 static int
sed1356_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)342 sed1356_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
343 {
344           struct sed1356_softc *sc = (struct sed1356_softc *)v;
345           struct hpcfb_fbconf *fbconf;
346           struct hpcfb_dspconf *dspconf;
347           struct wsdisplay_param *dispparam;
348 
349           switch (cmd) {
350           case WSDISPLAYIO_GETCMAP:
351           case WSDISPLAYIO_PUTCMAP:
352                     /*
353                      * XXX should be able to handle color map in 4/8 bpp mode.
354                      */
355                     return EINVAL;
356 
357           case WSDISPLAYIO_SVIDEO:
358                     if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
359                               sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
360                     else
361                               sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
362                     sed1356_update_powerstate(sc, PWRSTAT_ALL);
363                     return 0;
364 
365           case WSDISPLAYIO_GVIDEO:
366                     *(int *)data = (sc->sc_powerstate & PWRSTAT_VIDEOOFF) ?
367                                         WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
368                     return 0;
369 
370           case WSDISPLAYIO_GETPARAM:
371                     dispparam = (struct wsdisplay_param *)data;
372                     switch (dispparam->param) {
373                     case WSDISPLAYIO_PARAM_BACKLIGHT:
374                               VPRINTF(("sed1356_ioctl: GET:BACKLIGHT\n"));
375                               sed1356_init_brightness(sc, 0);
376                               sed1356_init_backlight(sc, 0);
377                               VPRINTF(("sed1356_ioctl: GET:(real)BACKLIGHT %d\n",
378                                   (sc->sc_powerstate & PWRSTAT_BACKLIGHT) ? 1: 0));
379                               dispparam->min = 0;
380                               dispparam->max = 1;
381                               if (sc->sc_max_brightness > 0)
382                                         dispparam->curval = (sc->sc_brightness > 0) ?
383                                             1 : 0;
384                               else
385                                         dispparam->curval =
386                                             (sc->sc_powerstate & PWRSTAT_BACKLIGHT) ?
387                                             1 : 0;
388                               VPRINTF(("sed1356_ioctl: GET:BACKLIGHT:%d(%s)\n",
389                                   dispparam->curval, (sc->sc_max_brightness > 0) ?
390                                   "brightness": "light"));
391                               return 0;
392 
393                     case WSDISPLAYIO_PARAM_CONTRAST:
394                               VPRINTF(("sed1356_ioctl: GET:CONTRAST\n"));
395                               sed1356_init_contrast(sc, 0);
396                               if (sc->sc_max_contrast > 0) {
397                                         dispparam->min = 0;
398                                         dispparam->max = sc->sc_max_contrast;
399                                         dispparam->curval = sc->sc_contrast;
400                                         VPRINTF(("sed1356_ioctl: GET:CONTRAST max=%d,"
401                                             " current=%d\n", sc->sc_max_contrast,
402                                             sc->sc_contrast));
403                                         return 0;
404                               }
405                               VPRINTF(("sed1356_ioctl: GET:CONTRAST EINVAL\n"));
406                               return EINVAL;
407 
408                     case WSDISPLAYIO_PARAM_BRIGHTNESS:
409                               VPRINTF(("sed1356_ioctl: GET:BRIGHTNESS\n"));
410                               sed1356_init_brightness(sc, 0);
411                               if (sc->sc_max_brightness > 0) {
412                                         dispparam->min = 0;
413                                         dispparam->max = sc->sc_max_brightness;
414                                         dispparam->curval = sc->sc_brightness;
415                                         VPRINTF(("sed1356_ioctl: GET:BRIGHTNESS max=%d,"
416                                             " current=%d\n", sc->sc_max_brightness,
417                                             sc->sc_brightness));
418                                         return 0;
419                               }
420                               VPRINTF(("sed1356_ioctl: GET:BRIGHTNESS EINVAL\n"));
421                               return EINVAL;
422 
423                     default:
424                               return EINVAL;
425                     }
426                     break;
427 
428           case WSDISPLAYIO_SETPARAM:
429                     dispparam = (struct wsdisplay_param*)data;
430                     switch (dispparam->param) {
431                     case WSDISPLAYIO_PARAM_BACKLIGHT:
432                               VPRINTF(("sed1356_ioctl: SET:BACKLIGHT\n"));
433                               if (dispparam->curval < 0 || 1 < dispparam->curval)
434                                         return EINVAL;
435                               sed1356_init_brightness(sc, 0);
436                               VPRINTF(("sed1356_ioctl: SET:max brightness=%d\n",
437                                   sc->sc_max_brightness));
438                               if (sc->sc_max_brightness > 0) { /* dimmer */
439                                         if (dispparam->curval == 0){
440                                                   sc->sc_brightness_save =
441                                                       sc->sc_brightness;
442                                                   sed1356_set_brightness(sc, 0); /* min */
443                                         } else {
444                                                   if (sc->sc_brightness_save == 0)
445                                                             sc->sc_brightness_save =
446                                                                 sc->sc_max_brightness;
447                                                   sed1356_set_brightness(sc,
448                                                       sc->sc_brightness_save);
449                                         }
450                                         VPRINTF(("sed1356_ioctl: SET:BACKLIGHT:"
451                                             "brightness=%d\n", sc->sc_brightness));
452                               } else { /* off */
453                                         if (dispparam->curval == 0)
454                                                   sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
455                                         else
456                                                   sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
457                                         VPRINTF(("sed1356_ioctl: SET:BACKLIGHT:"
458                                             "powerstate %d\n", (sc->sc_powerstate &
459                                             PWRSTAT_BACKLIGHT) ? 1 : 0));
460                                         sed1356_update_powerstate(sc, PWRSTAT_BACKLIGHT);
461                                         VPRINTF(("sed1356_ioctl: SET:BACKLIGHT:%d\n",
462                                             (sc->sc_powerstate & PWRSTAT_BACKLIGHT) ?
463                                             1 : 0));
464                               }
465                               return 0;
466 
467                     case WSDISPLAYIO_PARAM_CONTRAST:
468                               VPRINTF(("sed1356_ioctl: SET:CONTRAST\n"));
469                               sed1356_init_contrast(sc, 0);
470                               if (dispparam->curval < 0 ||
471                                   sc->sc_max_contrast < dispparam->curval)
472                                         return EINVAL;
473                               if (sc->sc_max_contrast > 0) {
474                                         VPRINTF(("sed1356_ioctl: SET:CONTRAST org=%d",
475                                             sc->sc_contrast));
476                                         sed1356_set_contrast(sc, dispparam->curval);
477                                         VPRINTF((", current=%d\n", sc->sc_contrast));
478                                         return 0;
479                               }
480                               VPRINTF(("sed1356_ioctl: SET:CONTRAST EINVAL\n"));
481                               return EINVAL;
482 
483                     case WSDISPLAYIO_PARAM_BRIGHTNESS:
484                               VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS\n"));
485                               sed1356_init_brightness(sc, 0);
486                               if (dispparam->curval < 0 ||
487                                   sc->sc_max_brightness < dispparam->curval)
488                                         return EINVAL;
489                               if (sc->sc_max_brightness > 0) {
490                                         VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS org=%d",
491                                             sc->sc_brightness));
492                                         sed1356_set_brightness(sc, dispparam->curval);
493                                         VPRINTF((", current=%d\n", sc->sc_brightness));
494                                         return 0;
495                               }
496                               VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS EINVAL\n"));
497                               return EINVAL;
498 
499                     default:
500                               return EINVAL;
501                     }
502                     return 0;
503 
504           case HPCFBIO_GCONF:
505                     fbconf = (struct hpcfb_fbconf *)data;
506                     if (fbconf->hf_conf_index != 0 &&
507                         fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
508                               return EINVAL;
509                     }
510                     *fbconf = sc->sc_fbconf;      /* structure assignment */
511                     return 0;
512           case HPCFBIO_SCONF:
513                     fbconf = (struct hpcfb_fbconf *)data;
514                     if (fbconf->hf_conf_index != 0 &&
515                         fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
516                               return EINVAL;
517                     }
518                     /*
519                      * nothing to do because we have only one configuration
520                      */
521                     return 0;
522           case HPCFBIO_GDSPCONF:
523                     dspconf = (struct hpcfb_dspconf *)data;
524                     if ((dspconf->hd_unit_index != 0 &&
525                          dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
526                         (dspconf->hd_conf_index != 0 &&
527                          dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
528                               return EINVAL;
529                     }
530                     *dspconf = sc->sc_dspconf;    /* structure assignment */
531                     return 0;
532           case HPCFBIO_SDSPCONF:
533                     dspconf = (struct hpcfb_dspconf *)data;
534                     if ((dspconf->hd_unit_index != 0 &&
535                          dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
536                         (dspconf->hd_conf_index != 0 &&
537                          dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
538                               return EINVAL;
539                     }
540                     /*
541                      * nothing to do
542                      * because we have only one unit and one configuration
543                      */
544                     return 0;
545           case HPCFBIO_GOP:
546           case HPCFBIO_SOP:
547                     /*
548                      * currently not implemented...
549                      */
550                     return EINVAL;
551           }
552 
553           return EPASSTHROUGH;
554 }
555 
556 static paddr_t
sed1356_mmap(void * ctx,off_t offset,int prot)557 sed1356_mmap(void *ctx, off_t offset, int prot)
558 {
559           struct sed1356_softc *sc = (struct sed1356_softc *)ctx;
560 
561           if (offset < 0 ||
562               (sc->sc_fbconf.hf_bytes_per_plane +
563                sc->sc_fbconf.hf_offset) < offset)
564                     return -1;
565 
566           return __BTOP((u_long)bootinfo->fb_addr + offset);
567 }
568 
569 static void
sed1356_init_backlight(struct sed1356_softc * sc,int inattach)570 sed1356_init_backlight(struct sed1356_softc *sc, int inattach)
571 {
572           int val = -1;
573 
574           if (sc->sc_lcd_inited & BACKLIGHT_INITED)
575                     return;
576 
577           if (config_hook_call(CONFIG_HOOK_GET,
578               CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
579                     /* we can get real light state */
580                     VPRINTF(("sed1356_init_backlight: real backlight=%d\n", val));
581                     if (val == 0)
582                               sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
583                     else
584                               sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
585                     sc->sc_lcd_inited |= BACKLIGHT_INITED;
586           } else if (inattach) {
587                     /*
588                        we cannot get real light state in attach time
589                        because light device not yet attached.
590                        we will retry in !inattach.
591                        temporary assume light is on.
592                      */
593                     sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
594           } else {
595                     /* we cannot get real light state, so work by myself state */
596                     sc->sc_lcd_inited |= BACKLIGHT_INITED;
597           }
598 }
599 
600 void
sed1356_init_brightness(struct sed1356_softc * sc,int inattach)601 sed1356_init_brightness(struct sed1356_softc *sc, int inattach)
602 {
603           int val = -1;
604 
605           if (sc->sc_lcd_inited & BRIGHTNESS_INITED)
606                     return;
607 
608           VPRINTF(("sed1356_init_brightness\n"));
609           if (config_hook_call(CONFIG_HOOK_GET,
610               CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
611                     /* we can get real brightness max */
612                     VPRINTF(("sed1356_init_brightness: "
613                         "real brightness max=%d\n", val));
614                     sc->sc_max_brightness = val;
615                     val = -1;
616                     if (config_hook_call(CONFIG_HOOK_GET,
617                         CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
618                               /* we can get real brightness */
619                               VPRINTF(("sed1356_init_brightness: "
620                                   "real brightness=%d\n", val));
621                               sc->sc_brightness_save = sc->sc_brightness = val;
622                     } else {
623                               sc->sc_brightness_save =
624                               sc->sc_brightness = sc->sc_max_brightness;
625                     }
626                     sc->sc_lcd_inited |= BRIGHTNESS_INITED;
627           } else if (inattach) {
628                     /*
629                      * we cannot get real brightness in attach time
630                      * because brightness device not yet attached.
631                      * we will retry in !inattach.
632                      */
633                     sc->sc_max_brightness = -1;
634                     sc->sc_brightness = -1;
635                     sc->sc_brightness_save = -1;
636           } else {
637                     /* we cannot get real brightness */
638                     sc->sc_lcd_inited |= BRIGHTNESS_INITED;
639           }
640 }
641 
642 void
sed1356_init_contrast(struct sed1356_softc * sc,int inattach)643 sed1356_init_contrast(struct sed1356_softc *sc, int inattach)
644 {
645           int val = -1;
646 
647           if (sc->sc_lcd_inited & CONTRAST_INITED)
648                     return;
649 
650           VPRINTF(("sed1356_init_contrast\n"));
651           if (config_hook_call(CONFIG_HOOK_GET,
652               CONFIG_HOOK_CONTRAST_MAX, &val) != -1) {
653                     /* we can get real contrast max */
654                     VPRINTF(("sed1356_init_contrast: "
655                         "real contrast max=%d\n", val));
656                     sc->sc_max_contrast = val;
657                     val = -1;
658                     if (config_hook_call(CONFIG_HOOK_GET,
659                         CONFIG_HOOK_CONTRAST, &val) != -1) {
660                               /* we can get real contrast */
661                               VPRINTF(("sed1356_init_contrast: "
662                                   "real contrast=%d\n", val));
663                               sc->sc_contrast = val;
664                     } else {
665                               sc->sc_contrast = sc->sc_max_contrast;
666                     }
667                     sc->sc_lcd_inited |= CONTRAST_INITED;
668           } else if (inattach) {
669                     /*
670                      * we cannot get real contrast in attach time
671                      * because contrast device not yet attached.
672                      * we will retry in !inattach.
673                      */
674                     sc->sc_max_contrast = -1;
675                     sc->sc_contrast = -1;
676           } else {
677                     /* we cannot get real contrast */
678                     sc->sc_lcd_inited |= CONTRAST_INITED;
679           }
680 }
681 
682 static void
sed1356_set_brightness(struct sed1356_softc * sc,int val)683 sed1356_set_brightness(struct sed1356_softc *sc, int val)
684 {
685           sc->sc_brightness = val;
686 
687           config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
688           if (config_hook_call(CONFIG_HOOK_GET,
689               CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
690                     sc->sc_brightness = val;
691           }
692 }
693 
694 static void
sed1356_set_contrast(struct sed1356_softc * sc,int val)695 sed1356_set_contrast(struct sed1356_softc *sc, int val)
696 {
697           sc->sc_contrast = val;
698 
699           config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
700           if (config_hook_call(CONFIG_HOOK_GET,
701               CONFIG_HOOK_CONTRAST, &val) != -1) {
702                     sc->sc_contrast = val;
703           }
704 }
705 
706 void
sed1356_toggle_lcdlight(void)707 sed1356_toggle_lcdlight(void)
708 {
709           struct sed1356_softc *sc = device_lookup_private(&sed_cd, 0);
710 
711           if (sc->sc_powerstate & PWRSTAT_VIDEOOFF)
712                     sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
713           else
714                     sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
715 
716           sed1356_update_powerstate(sc, PWRSTAT_ALL);
717 }
718