^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * linux/drivers/video/amba-clcd.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2001 ARM Limited, by David A Rusling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Updated to 2.5, Deep Blue Solutions Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * License. See the file COPYING in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * ARM PrimeCell PL110 Color LCD Controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/amba/bus.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/amba/clcd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/of_graph.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <video/display_timing.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <video/of_display_timing.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <video/videomode.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define to_clcd(info) container_of(info, struct clcd_fb, fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* This is limited to 16 characters when displayed by X startup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static const char *clcd_name = "CLCD FB";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * Unfortunately, the enable/disable functions may be called either from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * process or IRQ context, and we _need_ to delay. This is _not_ good.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static inline void clcdfb_sleep(unsigned int ms)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (in_atomic()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) mdelay(ms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) msleep(ms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static inline void clcdfb_set_start(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) unsigned long ustart = fb->fb.fix.smem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) unsigned long lstart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) writel(ustart, fb->regs + CLCD_UBAS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) writel(lstart, fb->regs + CLCD_LBAS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static void clcdfb_disable(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (fb->board->disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) fb->board->disable(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (fb->panel->backlight) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) fb->panel->backlight->props.power = FB_BLANK_POWERDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) backlight_update_status(fb->panel->backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) val = readl(fb->regs + fb->off_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (val & CNTL_LCDPWR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) val &= ~CNTL_LCDPWR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) writel(val, fb->regs + fb->off_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) clcdfb_sleep(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (val & CNTL_LCDEN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) val &= ~CNTL_LCDEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) writel(val, fb->regs + fb->off_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * Disable CLCD clock source.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (fb->clk_enabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) fb->clk_enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) clk_disable(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * Enable the CLCD clock source.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (!fb->clk_enabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) fb->clk_enabled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) clk_enable(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * Bring up by first enabling..
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) cntl |= CNTL_LCDEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) writel(cntl, fb->regs + fb->off_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) clcdfb_sleep(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * and now apply power.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) cntl |= CNTL_LCDPWR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) writel(cntl, fb->regs + fb->off_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * Turn on backlight
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (fb->panel->backlight) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) fb->panel->backlight->props.power = FB_BLANK_UNBLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) backlight_update_status(fb->panel->backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * finally, enable the interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (fb->board->enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) fb->board->enable(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) u32 caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (fb->panel->caps && fb->board->caps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) caps = fb->panel->caps & fb->board->caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* Old way of specifying what can be used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) caps = fb->panel->cntl & CNTL_BGR ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) CLCD_CAP_BGR : CLCD_CAP_RGB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /* But mask out 444 modes as they weren't supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) caps &= ~CLCD_CAP_444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* Only TFT panels can do RGB888/BGR888 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (!(fb->panel->cntl & CNTL_LCDTFT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) caps &= ~CLCD_CAP_888;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) memset(&var->transp, 0, sizeof(var->transp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) var->red.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) var->green.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) var->blue.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /* If we can't do 5551, reject */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) caps &= CLCD_CAP_5551;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (!caps) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) var->red.length = var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) var->red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) var->green.length = var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) var->green.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) var->blue.length = var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /* If we can't do 444, 5551 or 565, reject */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * Green length can be 4, 5 or 6 depending whether
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * we're operating in 444, 5551 or 565 mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (var->green.length == 4 && caps & CLCD_CAP_444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) caps &= CLCD_CAP_444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (var->green.length == 5 && caps & CLCD_CAP_5551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) caps &= CLCD_CAP_5551;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) else if (var->green.length == 6 && caps & CLCD_CAP_565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) caps &= CLCD_CAP_565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * PL110 officially only supports RGB555,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * but may be wired up to allow RGB565.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (caps & CLCD_CAP_565) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) var->green.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) caps &= CLCD_CAP_565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) } else if (caps & CLCD_CAP_5551) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) var->green.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) caps &= CLCD_CAP_5551;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) var->green.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) caps &= CLCD_CAP_444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (var->green.length >= 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) var->red.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) var->blue.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) /* If we can't do 888, reject */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) caps &= CLCD_CAP_888;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (!caps) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * >= 16bpp displays have separate colour component bitfields
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * encoded in the pixel data. Calculate their position from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * the bitfield length defined above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (ret == 0 && var->bits_per_pixel >= 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) bool bgr, rgb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) rgb = caps & CLCD_CAP_RGB && var->red.offset == 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (!bgr && !rgb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * The requested format was not possible, try just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * our capabilities. One of BGR or RGB must be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * supported.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) bgr = caps & CLCD_CAP_BGR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (bgr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) var->green.offset = var->blue.offset + var->blue.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) var->red.offset = var->green.offset + var->green.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) var->red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) var->green.offset = var->red.offset + var->red.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) var->blue.offset = var->green.offset + var->green.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) struct clcd_fb *fb = to_clcd(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (fb->board->check)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) ret = fb->board->check(fb, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (ret == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) var->xres_virtual * var->bits_per_pixel / 8 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) var->yres_virtual > fb->fb.fix.smem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) ret = clcdfb_set_bitfields(fb, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) static int clcdfb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct clcd_fb *fb = to_clcd(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct clcd_regs regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) fb->fb.fix.line_length = fb->fb.var.xres_virtual *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) fb->fb.var.bits_per_pixel / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (fb->fb.var.bits_per_pixel <= 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) fb->board->decode(fb, ®s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) clcdfb_disable(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) writel(regs.tim0, fb->regs + CLCD_TIM0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) writel(regs.tim1, fb->regs + CLCD_TIM1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) writel(regs.tim2, fb->regs + CLCD_TIM2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) writel(regs.tim3, fb->regs + CLCD_TIM3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) clcdfb_set_start(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) fb->clcd_cntl = regs.cntl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) clcdfb_enable(fb, regs.cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) printk(KERN_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) "CLCD: Registers set to\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) " %08x %08x %08x %08x\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) " %08x %08x %08x %08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) unsigned int mask = (1 << bf->length) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) return (val >> (16 - bf->length) & mask) << bf->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) * Set a single color register. The values supplied have a 16 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) * magnitude. Return != 0 for invalid regno.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) unsigned int blue, unsigned int transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) struct clcd_fb *fb = to_clcd(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (regno < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) convert_bitfield(blue, &fb->fb.var.blue) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) convert_bitfield(green, &fb->fb.var.green) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) convert_bitfield(red, &fb->fb.var.red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) u32 val, mask, newval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) newval = (red >> 11) & 0x001f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) newval |= (green >> 6) & 0x03e0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) newval |= (blue >> 1) & 0x7c00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * 3.2.11: if we're configured for big endian
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) * byte order, the palette entries are swapped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (fb->clcd_cntl & CNTL_BEBO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) regno ^= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (regno & 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) newval <<= 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) mask = 0x0000ffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) mask = 0xffff0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) val = readl(fb->regs + hw_reg) & mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) writel(val | newval, fb->regs + hw_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return regno > 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) * then the caller blanks by setting the CLUT (Color Look Up Table) to all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * to e.g. a video mode which doesn't support it. Implements VESA suspend
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * and powerdown modes on hardware that supports disabling hsync/vsync:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) * blank_mode == 2: suspend vsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * blank_mode == 3: suspend hsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * blank_mode == 4: powerdown
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) static int clcdfb_blank(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) struct clcd_fb *fb = to_clcd(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (blank_mode != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) clcdfb_disable(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) clcdfb_enable(fb, fb->clcd_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) static int clcdfb_mmap(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) struct clcd_fb *fb = to_clcd(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) len = info->fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) fb->board->mmap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) ret = fb->board->mmap(fb, vma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) static const struct fb_ops clcdfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) .fb_check_var = clcdfb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) .fb_set_par = clcdfb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) .fb_setcolreg = clcdfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) .fb_blank = clcdfb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) .fb_mmap = clcdfb_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) static int clcdfb_register(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) * ARM PL111 always has IENB at 0x1c; it's only PL110
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) * which is reversed on some platforms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) fb->off_ienb = CLCD_PL111_IENB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) fb->off_cntl = CLCD_PL111_CNTL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) fb->off_ienb = CLCD_PL110_IENB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) fb->off_cntl = CLCD_PL110_CNTL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) fb->clk = clk_get(&fb->dev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (IS_ERR(fb->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) ret = PTR_ERR(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) ret = clk_prepare(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) goto free_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) fb->fb.device = &fb->dev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) fb->fb.fix.mmio_start = fb->dev->res.start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) fb->fb.fix.mmio_len = resource_size(&fb->dev->res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (!fb->regs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) printk(KERN_ERR "CLCD: unable to remap registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) goto clk_unprep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) fb->fb.fbops = &clcdfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) fb->fb.flags = FBINFO_FLAG_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) fb->fb.pseudo_palette = fb->cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) fb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) fb->fb.fix.type_aux = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) fb->fb.fix.xpanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) fb->fb.fix.ypanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) fb->fb.fix.ywrapstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) fb->fb.fix.accel = FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) fb->fb.var.xres = fb->panel->mode.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) fb->fb.var.yres = fb->panel->mode.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) fb->fb.var.xres_virtual = fb->panel->mode.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) fb->fb.var.yres_virtual = fb->panel->mode.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) fb->fb.var.bits_per_pixel = fb->panel->bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) fb->fb.var.grayscale = fb->panel->grayscale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) fb->fb.var.pixclock = fb->panel->mode.pixclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) fb->fb.var.left_margin = fb->panel->mode.left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) fb->fb.var.right_margin = fb->panel->mode.right_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) fb->fb.var.upper_margin = fb->panel->mode.upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) fb->fb.var.lower_margin = fb->panel->mode.lower_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) fb->fb.var.hsync_len = fb->panel->mode.hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) fb->fb.var.vsync_len = fb->panel->mode.vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) fb->fb.var.sync = fb->panel->mode.sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) fb->fb.var.vmode = fb->panel->mode.vmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) fb->fb.var.activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) fb->fb.var.nonstd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) fb->fb.var.height = fb->panel->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) fb->fb.var.width = fb->panel->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) fb->fb.var.accel_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) fb->fb.monspecs.hfmin = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) fb->fb.monspecs.hfmax = 100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) fb->fb.monspecs.vfmin = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) fb->fb.monspecs.vfmax = 400;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) fb->fb.monspecs.dclkmin = 1000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) fb->fb.monspecs.dclkmax = 100000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) * Make sure that the bitfields are set appropriately.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) clcdfb_set_bitfields(fb, &fb->fb.var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) * Allocate colourmap.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) goto unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) * Ensure interrupts are disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) writel(0, fb->regs + fb->off_ienb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) fb_set_var(&fb->fb, &fb->fb.var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) dev_info(&fb->dev->dev, "%s hardware, %s display\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) fb->board->name, fb->panel->mode.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) ret = register_framebuffer(&fb->fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) fb_dealloc_cmap(&fb->fb.cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) unmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) iounmap(fb->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) clk_unprep:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) clk_unprepare(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) free_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) clk_put(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) #ifdef CONFIG_OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) static int clcdfb_of_get_dpi_panel_mode(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) struct clcd_panel *clcd_panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) struct display_timing timing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) struct videomode video;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) err = of_get_display_timing(node, "panel-timing", &timing);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) pr_err("%pOF: problems parsing panel-timing (%d)\n", node, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) videomode_from_timing(&timing, &video);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) err = fb_videomode_from_videomode(&video, &clcd_panel->mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) /* Set up some inversion flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) clcd_panel->tim2 |= TIM2_IPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) else if (!(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) * To preserve backwards compatibility, the IPC (inverted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) * pixel clock) flag needs to be set on any display that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) * doesn't explicitly specify that the pixel clock is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) * active on the negative or positive edge.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) clcd_panel->tim2 |= TIM2_IPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) clcd_panel->tim2 |= TIM2_IHS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) clcd_panel->tim2 |= TIM2_IVS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (timing.flags & DISPLAY_FLAGS_DE_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) clcd_panel->tim2 |= TIM2_IOE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) static int clcdfb_snprintf_mode(char *buf, int size, struct fb_videomode *mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) return snprintf(buf, size, "%ux%u@%u", mode->xres, mode->yres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) mode->refresh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) static int clcdfb_of_get_backlight(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) struct clcd_panel *clcd_panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) struct backlight_device *backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) /* Look up the optional backlight device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) backlight = devm_of_find_backlight(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if (IS_ERR(backlight))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) return PTR_ERR(backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) clcd_panel->backlight = backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) static int clcdfb_of_get_mode(struct device *dev, struct device_node *panel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) struct clcd_panel *clcd_panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) struct fb_videomode *mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) /* Only directly connected DPI panels supported for now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) if (of_device_is_compatible(panel, "panel-dpi"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) err = clcdfb_of_get_dpi_panel_mode(panel, clcd_panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) err = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) mode = &clcd_panel->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) len = clcdfb_snprintf_mode(NULL, 0, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (!name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) clcdfb_snprintf_mode(name, len + 1, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) mode->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) static struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) unsigned int part;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) u32 r0, g0, b0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) u32 caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) } panels[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) { 0x110, 1, 7, 13, CLCD_CAP_5551 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) { 0x110, 0, 8, 16, CLCD_CAP_888 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) { 0x110, 16, 8, 0, CLCD_CAP_888 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) { 0x111, 4, 14, 20, CLCD_CAP_444 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) { 0x111, 3, 11, 19, CLCD_CAP_444 | CLCD_CAP_5551 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) { 0x111, 3, 10, 19, CLCD_CAP_444 | CLCD_CAP_5551 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) CLCD_CAP_565 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) { 0x111, 0, 8, 16, CLCD_CAP_444 | CLCD_CAP_5551 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) CLCD_CAP_565 | CLCD_CAP_888 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) /* Bypass pixel clock divider */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) fb->panel->tim2 |= TIM2_BCD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) /* TFT display, vert. comp. interrupt at the start of the back porch */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) fb->panel->caps = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) /* Match the setup with known variants */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) for (i = 0; i < ARRAY_SIZE(panels) && !fb->panel->caps; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (amba_part(fb->dev) != panels[i].part)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) if (g0 != panels[i].g0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (r0 == panels[i].r0 && b0 == panels[i].b0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) fb->panel->caps = panels[i].caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * If we actually physically connected the R lines to B and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) * vice versa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) if (r0 != 0 && b0 == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) fb->panel->bgr_connection = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) return fb->panel->caps ? 0 : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) static int clcdfb_of_init_display(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) struct device_node *endpoint, *panel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) unsigned int bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) u32 max_bandwidth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) u32 tft_r0b0g0[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) if (!fb->panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) * Fetch the panel endpoint.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) if (!endpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) panel = of_graph_get_remote_port_parent(endpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) if (!panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) err = clcdfb_of_get_backlight(&fb->dev->dev, fb->panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) err = clcdfb_of_get_mode(&fb->dev->dev, panel, fb->panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) err = of_property_read_u32(fb->dev->dev.of_node, "max-memory-bandwidth",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) &max_bandwidth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) if (!err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) * max_bandwidth is in bytes per second and pixclock in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) * pico-seconds, so the maximum allowed bits per pixel is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) * 8 * max_bandwidth / (PICOS2KHZ(pixclock) * 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) * Rearrange this calculation to avoid overflow and then ensure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) * result is a valid format.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) bpp = max_bandwidth / (1000 / 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) / PICOS2KHZ(fb->panel->mode.pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) bpp = rounddown_pow_of_two(bpp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) if (bpp > 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) bpp = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) bpp = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) fb->panel->bpp = bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) #ifdef CONFIG_CPU_BIG_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) fb->panel->cntl |= CNTL_BEBO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) fb->panel->width = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) fb->panel->height = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) if (of_property_read_u32_array(endpoint,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) "arm,pl11x,tft-r0g0b0-pads",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) tft_r0b0g0[1], tft_r0b0g0[2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) static int clcdfb_of_vram_setup(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) struct device_node *memory;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) u64 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) err = clcdfb_of_init_display(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) memory = of_parse_phandle(fb->dev->dev.of_node, "memory-region", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (!memory)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) fb->fb.screen_base = of_iomap(memory, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) if (!fb->fb.screen_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) fb->fb.fix.smem_start = of_translate_address(memory,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) of_get_address(memory, 0, &size, NULL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) fb->fb.fix.smem_len = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) unsigned long off, user_size, kernel_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) off = vma->vm_pgoff << PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) user_size = vma->vm_end - vma->vm_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) kernel_size = fb->fb.fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) if (off >= kernel_size || user_size > (kernel_size - off))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) return remap_pfn_range(vma, vma->vm_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) __phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) user_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) pgprot_writecombine(vma->vm_page_prot));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) static void clcdfb_of_vram_remove(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) iounmap(fb->fb.screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) static int clcdfb_of_dma_setup(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) unsigned long framesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) dma_addr_t dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) err = clcdfb_of_init_display(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) framesize = PAGE_ALIGN(fb->panel->mode.xres * fb->panel->mode.yres *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) fb->panel->bpp / 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) &dma, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) if (!fb->fb.screen_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) fb->fb.fix.smem_start = dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) fb->fb.fix.smem_len = framesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) fb->fb.fix.smem_start, fb->fb.fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) static void clcdfb_of_dma_remove(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) dma_free_coherent(&fb->dev->dev, fb->fb.fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) fb->fb.screen_base, fb->fb.fix.smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) struct device_node *node = dev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (!board)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) board->name = of_node_full_name(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) board->caps = CLCD_CAP_ALL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) board->check = clcdfb_check;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) board->decode = clcdfb_decode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) if (of_find_property(node, "memory-region", NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) board->setup = clcdfb_of_vram_setup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) board->mmap = clcdfb_of_vram_mmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) board->remove = clcdfb_of_vram_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) board->setup = clcdfb_of_dma_setup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) board->mmap = clcdfb_of_dma_mmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) board->remove = clcdfb_of_dma_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) return board;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) struct clcd_board *board = dev_get_platdata(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) struct clcd_fb *fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) if (!board)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) board = clcdfb_of_get_board(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) if (!board)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) ret = amba_request_regions(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) printk(KERN_ERR "CLCD: unable to reserve regs region\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) fb = kzalloc(sizeof(*fb), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) if (!fb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) goto free_region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) fb->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) fb->board = board;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) dev_info(&fb->dev->dev, "PL%03x designer %02x rev%u at 0x%08llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) amba_part(dev), amba_manf(dev), amba_rev(dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) (unsigned long long)dev->res.start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) ret = fb->board->setup(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) goto free_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) ret = clcdfb_register(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) amba_set_drvdata(dev, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) fb->board->remove(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) free_fb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) kfree(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) free_region:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) amba_release_regions(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) static void clcdfb_remove(struct amba_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) struct clcd_fb *fb = amba_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) clcdfb_disable(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) unregister_framebuffer(&fb->fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) if (fb->fb.cmap.len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) fb_dealloc_cmap(&fb->fb.cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) iounmap(fb->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) clk_unprepare(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) clk_put(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) fb->board->remove(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) kfree(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) amba_release_regions(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) static const struct amba_id clcdfb_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) .id = 0x00041110,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) .mask = 0x000ffffe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) { 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) MODULE_DEVICE_TABLE(amba, clcdfb_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) static struct amba_driver clcd_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) .drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) .name = "clcd-pl11x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) .probe = clcdfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) .remove = clcdfb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) .id_table = clcdfb_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) static int __init amba_clcdfb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) if (fb_get_options("ambafb", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) return amba_driver_register(&clcd_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) module_init(amba_clcdfb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) static void __exit amba_clcdfb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) amba_driver_unregister(&clcd_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) module_exit(amba_clcdfb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) MODULE_LICENSE("GPL");