^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* linux/drivers/video/s3c2410fb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Copyright (c) 2004,2005 Arnaud Patard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2004-2008 Ben Dooks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * S3C2410 LCD Framebuffer Driver
^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 for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Driver based on skeletonfb.c, sa1100fb.c and others.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/platform_data/fb-s3c2410.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <asm/div64.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <asm/mach/map.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include "s3c2410fb.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include "s3c2410fb-regs-lcd.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* Debugging stuff */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static int debug = IS_BUILTIN(CONFIG_FB_S3C2410_DEBUG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define dprintk(msg...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (debug) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) pr_debug(msg); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* useful functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static int is_s3c2412(struct s3c2410fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return (fbi->drv_type == DRV_S3C2412);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* s3c2410fb_set_lcdaddr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * initialise lcd controller address pointers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static void s3c2410fb_set_lcdaddr(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) unsigned long saddr1, saddr2, saddr3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct s3c2410fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) void __iomem *regs = fbi->io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) saddr1 = info->fix.smem_start >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) saddr2 = info->fix.smem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) saddr2 += info->fix.line_length * info->var.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) saddr2 >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) saddr3 = S3C2410_OFFSIZE(0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) S3C2410_PAGEWIDTH((info->fix.line_length / 2) & 0x3ff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) dprintk("LCDSADDR1 = 0x%08lx\n", saddr1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) dprintk("LCDSADDR2 = 0x%08lx\n", saddr2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) dprintk("LCDSADDR3 = 0x%08lx\n", saddr3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) writel(saddr1, regs + S3C2410_LCDSADDR1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) writel(saddr2, regs + S3C2410_LCDSADDR2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) writel(saddr3, regs + S3C2410_LCDSADDR3);
^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) /* s3c2410fb_calc_pixclk()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * calculate divisor for clk->pixclk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) unsigned long pixclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) unsigned long clk = fbi->clk_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) unsigned long long div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /* pixclk is in picoseconds, our clock is in Hz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * Hz -> picoseconds is / 10^-12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) div = (unsigned long long)clk * pixclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) div >>= 12; /* div / 2^12 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) do_div(div, 625 * 625UL * 625); /* div / 5^12 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) dprintk("pixclk %ld, divisor is %ld\n", pixclk, (long)div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * s3c2410fb_check_var():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * Get the video params out of 'var'. If a value doesn't fit, round it up,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * if it's too big, return -EINVAL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct s3c2410fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct s3c2410fb_mach_info *mach_info = dev_get_platdata(fbi->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) struct s3c2410fb_display *display = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct s3c2410fb_display *default_display = mach_info->displays +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) mach_info->default_display;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int type = default_display->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) unsigned i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) dprintk("check_var(var=%p, info=%p)\n", var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* validate x/y resolution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* choose default mode if possible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (var->yres == default_display->yres &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) var->xres == default_display->xres &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) var->bits_per_pixel == default_display->bpp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) display = default_display;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) for (i = 0; i < mach_info->num_displays; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (type == mach_info->displays[i].type &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) var->yres == mach_info->displays[i].yres &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) var->xres == mach_info->displays[i].xres &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) var->bits_per_pixel == mach_info->displays[i].bpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) display = mach_info->displays + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (!display) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) dprintk("wrong resolution or depth %dx%d at %d bpp\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) var->xres, var->yres, var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* it is always the size as the display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) var->xres_virtual = display->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) var->yres_virtual = display->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) var->height = display->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) var->width = display->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /* copy lcd settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) var->pixclock = display->pixclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) var->left_margin = display->left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) var->right_margin = display->right_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) var->upper_margin = display->upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) var->lower_margin = display->lower_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) var->vsync_len = display->vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) var->hsync_len = display->hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) fbi->regs.lcdcon5 = display->lcdcon5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /* set display type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) fbi->regs.lcdcon1 = display->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /* set r/g/b positions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) var->red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) var->red.length = var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) var->green = var->red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) var->blue = var->red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (display->type != S3C2410_LCDCON1_TFT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /* 8 bpp 332 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) var->red.length = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) var->red.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) var->green.length = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) var->green.offset = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) var->blue.length = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) var->red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) var->green = var->red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) var->blue = var->red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case 12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) /* 12 bpp 444 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) var->red.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) var->red.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) var->green.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) var->green.offset = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) var->blue.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (display->lcdcon5 & S3C2410_LCDCON5_FRM565) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) /* 16 bpp, 565 format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) var->red.offset = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) var->green.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) var->blue.offset = 0;
^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->green.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /* 16 bpp, 5551 format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) var->red.offset = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) var->green.offset = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) var->blue.offset = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) var->green.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /* 24 bpp 888 and 8 dummy */
^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->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) var->blue.offset = 0;
^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) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) /* s3c2410fb_calculate_stn_lcd_regs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * calculate register values from var settings
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) static void s3c2410fb_calculate_stn_lcd_regs(const struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) struct s3c2410fb_hw *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) const struct s3c2410fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) const struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) int type = regs->lcdcon1 & ~S3C2410_LCDCON1_TFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) int hs = var->xres >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) unsigned wdly = (var->left_margin >> 4) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) unsigned wlh = (var->hsync_len >> 4) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (type != S3C2410_LCDCON1_STN4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) hs >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) regs->lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) regs->lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) regs->lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) regs->lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) hs *= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) case 12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) regs->lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) hs *= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /* invalid pixel depth */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) dev_err(fbi->dev, "invalid bpp %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /* update X/Y info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) dprintk("setting horz: lft=%d, rt=%d, sync=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) var->left_margin, var->right_margin, var->hsync_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (wdly > 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) wdly = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (wlh > 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) wlh = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) regs->lcdcon3 = S3C2410_LCDCON3_WDLY(wdly) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) S3C2410_LCDCON3_LINEBLANK(var->right_margin / 8) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) S3C2410_LCDCON3_HOZVAL(hs - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) regs->lcdcon4 = S3C2410_LCDCON4_WLH(wlh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* s3c2410fb_calculate_tft_lcd_regs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) * calculate register values from var settings
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) static void s3c2410fb_calculate_tft_lcd_regs(const struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct s3c2410fb_hw *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) const struct s3c2410fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) const struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) regs->lcdcon5 |= S3C2410_LCDCON5_BSWP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) S3C2410_LCDCON5_FRM565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) regs->lcdcon5 &= ~S3C2410_LCDCON5_HWSWP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) regs->lcdcon5 &= ~S3C2410_LCDCON5_BSWP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) regs->lcdcon5 |= S3C2410_LCDCON5_HWSWP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) regs->lcdcon1 |= S3C2410_LCDCON1_TFT24BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) regs->lcdcon5 &= ~(S3C2410_LCDCON5_BSWP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) S3C2410_LCDCON5_HWSWP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) S3C2410_LCDCON5_BPP24BL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) /* invalid pixel depth */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) dev_err(fbi->dev, "invalid bpp %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) /* update X/Y info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) dprintk("setting vert: up=%d, low=%d, sync=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) var->upper_margin, var->lower_margin, var->vsync_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) dprintk("setting horz: lft=%d, rt=%d, sync=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) var->left_margin, var->right_margin, var->hsync_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) S3C2410_LCDCON2_VBPD(var->upper_margin - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) S3C2410_LCDCON2_VSPW(var->vsync_len - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) S3C2410_LCDCON3_HFPD(var->left_margin - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) S3C2410_LCDCON3_HOZVAL(var->xres - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) /* s3c2410fb_activate_var
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) * activate (set) the controller from the given framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) * information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) static void s3c2410fb_activate_var(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) struct s3c2410fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) void __iomem *regs = fbi->io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) int clkdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) clkdiv = DIV_ROUND_UP(s3c2410fb_calc_pixclk(fbi, var->pixclock), 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) dprintk("%s: var->xres = %d\n", __func__, var->xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) dprintk("%s: var->yres = %d\n", __func__, var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) dprintk("%s: var->bpp = %d\n", __func__, var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (type == S3C2410_LCDCON1_TFT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) --clkdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (clkdiv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) clkdiv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (clkdiv < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) clkdiv = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /* write new registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) dprintk("new register set:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) dprintk("lcdcon[1] = 0x%08lx\n", fbi->regs.lcdcon1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) dprintk("lcdcon[2] = 0x%08lx\n", fbi->regs.lcdcon2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) dprintk("lcdcon[3] = 0x%08lx\n", fbi->regs.lcdcon3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) regs + S3C2410_LCDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) /* set lcd address pointers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) s3c2410fb_set_lcdaddr(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) * s3c2410fb_set_par - Alters the hardware state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) * @info: frame buffer structure that represents a single frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) static int s3c2410fb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) case 12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) info->fix.visual = FB_VISUAL_MONO01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) /* activate this new configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) s3c2410fb_activate_var(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) static void schedule_palette_update(struct s3c2410fb_info *fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) unsigned int regno, unsigned int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) unsigned long irqen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) void __iomem *irq_base = fbi->irq_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) fbi->palette_buffer[regno] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (!fbi->palette_ready) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) fbi->palette_ready = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) /* enable IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) irqen = readl(irq_base + S3C24XX_LCDINTMSK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) irqen &= ~S3C2410_LCDINT_FRSYNC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) writel(irqen, irq_base + S3C24XX_LCDINTMSK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) /* from pxafb.c */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static inline unsigned int chan_to_field(unsigned int chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) struct fb_bitfield *bf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) chan &= 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) chan >>= 16 - bf->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) return chan << bf->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) static int s3c2410fb_setcolreg(unsigned regno,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) unsigned red, unsigned green, unsigned blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) unsigned transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) struct s3c2410fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) void __iomem *regs = fbi->io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) regno, red, green, blue); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) switch (info->fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) /* true-colour, use pseudo-palette */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) u32 *pal = info->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) val = chan_to_field(red, &info->var.red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) val |= chan_to_field(green, &info->var.green);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) val |= chan_to_field(blue, &info->var.blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) pal[regno] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) if (regno < 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) /* currently assume RGB 5-6-5 mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) val = (red >> 0) & 0xf800;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) val |= (green >> 5) & 0x07e0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) val |= (blue >> 11) & 0x001f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) writel(val, regs + S3C2410_TFTPAL(regno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) schedule_palette_update(fbi, regno, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return 1; /* unknown type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) /* s3c2410fb_lcd_enable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) * shutdown the lcd controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) static void s3c2410fb_lcd_enable(struct s3c2410fb_info *fbi, int enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if (enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) writel(fbi->regs.lcdcon1, fbi->io + S3C2410_LCDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) * s3c2410fb_blank
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) * @blank_mode: the blank mode we want.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) * @info: frame buffer structure that represents a single frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * Blank the screen if blank_mode != 0, else unblank. Return 0 if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * blanking succeeded, != 0 if un-/blanking failed due to e.g. a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * video mode which doesn't support it. Implements VESA suspend
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * and powerdown modes on hardware that supports disabling hsync/vsync:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * Returns negative errno on error, or zero on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) struct s3c2410fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) void __iomem *tpal_reg = fbi->io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (blank_mode == FB_BLANK_POWERDOWN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) s3c2410fb_lcd_enable(fbi, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) s3c2410fb_lcd_enable(fbi, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (blank_mode == FB_BLANK_UNBLANK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) writel(0x0, tpal_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) dprintk("setting TPAL to output 0x000000\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) writel(S3C2410_TPAL_EN, tpal_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) static int s3c2410fb_debug_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) return snprintf(buf, PAGE_SIZE, "%s\n", debug ? "on" : "off");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) static int s3c2410fb_debug_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (len < 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (strncasecmp(buf, "on", 2) == 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) strncasecmp(buf, "1", 1) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) debug = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) dev_dbg(dev, "s3c2410fb: Debug On");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) } else if (strncasecmp(buf, "off", 3) == 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) strncasecmp(buf, "0", 1) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) debug = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) dev_dbg(dev, "s3c2410fb: Debug Off");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) static DEVICE_ATTR(debug, 0664, s3c2410fb_debug_show, s3c2410fb_debug_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) static const struct fb_ops s3c2410fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) .fb_check_var = s3c2410fb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) .fb_set_par = s3c2410fb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) .fb_blank = s3c2410fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) .fb_setcolreg = s3c2410fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) * s3c2410fb_map_video_memory():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * Allocates the DRAM memory for the frame buffer. This buffer is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * remapped into a non-cached, non-buffered, memory region to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * allow palette and pixel writes to occur without flushing the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) * cache. Once this area is remapped, all virtual memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) * access to the video memory should occur at the new region.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) static int s3c2410fb_map_video_memory(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) struct s3c2410fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) dma_addr_t map_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) info->screen_base = dma_alloc_wc(fbi->dev, map_size, &map_dma,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) if (info->screen_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) /* prevent initial garbage on screen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) dprintk("map_video_memory: clear %p:%08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) info->screen_base, map_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) memset(info->screen_base, 0x00, map_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) info->fix.smem_start = map_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) dprintk("map_video_memory: dma=%08lx cpu=%p size=%08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) info->fix.smem_start, info->screen_base, map_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return info->screen_base ? 0 : -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) static inline void s3c2410fb_unmap_video_memory(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) struct s3c2410fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) info->screen_base, info->fix.smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) static inline void modify_gpio(void __iomem *reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) unsigned long set, unsigned long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) if (!reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) tmp = readl(reg) & ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) writel(tmp | set, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) * s3c2410fb_init_registers - Initialise all LCD-related registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) static int s3c2410fb_init_registers(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) struct s3c2410fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) struct s3c2410fb_mach_info *mach_info = dev_get_platdata(fbi->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) void __iomem *regs = fbi->io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) void __iomem *tpal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) void __iomem *lpcsel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) if (is_s3c2412(fbi)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) tpal = regs + S3C2412_TPAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) lpcsel = regs + S3C2412_TCONSEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) tpal = regs + S3C2410_TPAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) lpcsel = regs + S3C2410_LPCSEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) /* Initialise LCD with values from haret */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) /* modify the gpio(s) with interrupts set (bjd) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) modify_gpio(mach_info->gpcup_reg, mach_info->gpcup, mach_info->gpcup_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) modify_gpio(mach_info->gpccon_reg, mach_info->gpccon, mach_info->gpccon_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) modify_gpio(mach_info->gpdup_reg, mach_info->gpdup, mach_info->gpdup_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) modify_gpio(mach_info->gpdcon_reg, mach_info->gpdcon, mach_info->gpdcon_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) writel(mach_info->lpcsel, lpcsel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) dprintk("replacing TPAL %08x\n", readl(tpal));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) /* ensure temporary palette disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) writel(0x00, tpal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) void __iomem *regs = fbi->io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) fbi->palette_ready = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) for (i = 0; i < 256; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) unsigned long ent = fbi->palette_buffer[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if (ent == PALETTE_BUFF_CLEAR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) writel(ent, regs + S3C2410_TFTPAL(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) /* it seems the only way to know exactly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) * if the palette wrote ok, is to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) * to see if the value verifies ok
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) if (readw(regs + S3C2410_TFTPAL(i)) == ent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) fbi->palette_buffer[i] = PALETTE_BUFF_CLEAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) fbi->palette_ready = 1; /* retry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) struct s3c2410fb_info *fbi = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) void __iomem *irq_base = fbi->irq_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) if (lcdirq & S3C2410_LCDINT_FRSYNC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) if (fbi->palette_ready)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) s3c2410fb_write_palette(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) #ifdef CONFIG_ARM_S3C24XX_CPUFREQ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) unsigned long val, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) struct s3c2410fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) struct fb_info *fbinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) long delta_f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) info = container_of(nb, struct s3c2410fb_info, freq_transition);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) fbinfo = dev_get_drvdata(info->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) /* work out change, <0 for speed-up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) delta_f = info->clk_rate - clk_get_rate(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) (val == CPUFREQ_PRECHANGE && delta_f < 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) info->clk_rate = clk_get_rate(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) s3c2410fb_activate_var(fbinfo);
^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) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) info->freq_transition.notifier_call = s3c2410fb_cpufreq_transition;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) return cpufreq_register_notifier(&info->freq_transition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) CPUFREQ_TRANSITION_NOTIFIER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) cpufreq_unregister_notifier(&info->freq_transition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) CPUFREQ_TRANSITION_NOTIFIER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) static const char driver_name[] = "s3c2410fb";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) static int s3c24xxfb_probe(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) enum s3c_drv_type drv_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) struct s3c2410fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) struct s3c2410fb_display *display;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) struct fb_info *fbinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) struct s3c2410fb_mach_info *mach_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) u32 lcdcon1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) mach_info = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) if (mach_info == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) "no platform data for lcd, cannot attach\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) if (mach_info->default_display >= mach_info->num_displays) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) dev_err(&pdev->dev, "default is %d but only %d displays\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) mach_info->default_display, mach_info->num_displays);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) display = mach_info->displays + mach_info->default_display;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) if (irq < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) dev_err(&pdev->dev, "no irq for device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) if (!fbinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) platform_set_drvdata(pdev, fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) info = fbinfo->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) info->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) info->drv_type = drv_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) if (res == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) dev_err(&pdev->dev, "failed to get memory registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) goto dealloc_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) size = resource_size(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) info->mem = request_mem_region(res->start, size, pdev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) if (info->mem == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) dev_err(&pdev->dev, "failed to get memory region\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) goto dealloc_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) info->io = ioremap(res->start, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) if (info->io == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) dev_err(&pdev->dev, "ioremap() of registers failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) goto release_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) if (drv_type == DRV_S3C2412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) info->irq_base = info->io + S3C2412_LCDINTBASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) info->irq_base = info->io + S3C2410_LCDINTBASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) dprintk("devinit\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) strcpy(fbinfo->fix.id, driver_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) /* Stop the video */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) lcdcon1 = readl(info->io + S3C2410_LCDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) fbinfo->fix.type_aux = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) fbinfo->fix.xpanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) fbinfo->fix.ypanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) fbinfo->fix.ywrapstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) fbinfo->fix.accel = FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) fbinfo->var.nonstd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) fbinfo->var.activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) fbinfo->var.accel_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) fbinfo->fbops = &s3c2410fb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) fbinfo->flags = FBINFO_FLAG_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) fbinfo->pseudo_palette = &info->pseudo_pal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) for (i = 0; i < 256; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) ret = request_irq(irq, s3c2410fb_irq, 0, pdev->name, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) goto release_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) info->clk = clk_get(NULL, "lcd");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) if (IS_ERR(info->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) dev_err(&pdev->dev, "failed to get lcd clock source\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) ret = PTR_ERR(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) goto release_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) clk_prepare_enable(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) dprintk("got and enabled clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) usleep_range(1000, 1100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) info->clk_rate = clk_get_rate(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) /* find maximum required memory size for display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) for (i = 0; i < mach_info->num_displays; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) unsigned long smem_len = mach_info->displays[i].xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) smem_len *= mach_info->displays[i].yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) smem_len *= mach_info->displays[i].bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) smem_len >>= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) if (fbinfo->fix.smem_len < smem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) fbinfo->fix.smem_len = smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) /* Initialize video memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) ret = s3c2410fb_map_video_memory(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) goto release_clock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) dprintk("got video memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) fbinfo->var.xres = display->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) fbinfo->var.yres = display->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) fbinfo->var.bits_per_pixel = display->bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) s3c2410fb_init_registers(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) s3c2410fb_check_var(&fbinfo->var, fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) ret = s3c2410fb_cpufreq_register(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) dev_err(&pdev->dev, "Failed to register cpufreq\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) goto free_video_memory;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) ret = register_framebuffer(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) dev_err(&pdev->dev, "Failed to register framebuffer device: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) goto free_cpufreq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) /* create device files */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) ret = device_create_file(&pdev->dev, &dev_attr_debug);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) dev_err(&pdev->dev, "failed to add debug attribute\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) dev_info(&pdev->dev, "fb%d: %s frame buffer device\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) fbinfo->node, fbinfo->fix.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) free_cpufreq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) s3c2410fb_cpufreq_deregister(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) free_video_memory:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) s3c2410fb_unmap_video_memory(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) release_clock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) clk_disable_unprepare(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) clk_put(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) release_irq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) free_irq(irq, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) release_regs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) iounmap(info->io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) release_mem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) release_mem_region(res->start, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) dealloc_fb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) framebuffer_release(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) static int s3c2410fb_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) return s3c24xxfb_probe(pdev, DRV_S3C2410);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) static int s3c2412fb_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) return s3c24xxfb_probe(pdev, DRV_S3C2412);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) * Cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) static int s3c2410fb_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) struct fb_info *fbinfo = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) struct s3c2410fb_info *info = fbinfo->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) unregister_framebuffer(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) s3c2410fb_cpufreq_deregister(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) s3c2410fb_lcd_enable(info, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) usleep_range(1000, 1100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) s3c2410fb_unmap_video_memory(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) if (info->clk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) clk_disable_unprepare(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) clk_put(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) info->clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) free_irq(irq, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) iounmap(info->io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) release_mem_region(info->mem->start, resource_size(info->mem));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) framebuffer_release(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) /* suspend and resume support for the lcd controller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) struct fb_info *fbinfo = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) struct s3c2410fb_info *info = fbinfo->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) s3c2410fb_lcd_enable(info, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) /* sleep before disabling the clock, we need to ensure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) * the LCD DMA engine is not going to get back on the bus
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) * before the clock goes off again (bjd) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) usleep_range(1000, 1100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) clk_disable_unprepare(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) static int s3c2410fb_resume(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) struct fb_info *fbinfo = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) struct s3c2410fb_info *info = fbinfo->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) clk_prepare_enable(info->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) usleep_range(1000, 1100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) s3c2410fb_init_registers(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) /* re-activate our display after resume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) s3c2410fb_activate_var(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) s3c2410fb_blank(FB_BLANK_UNBLANK, fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) #define s3c2410fb_suspend NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) #define s3c2410fb_resume NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) static struct platform_driver s3c2410fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) .probe = s3c2410fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) .remove = s3c2410fb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) .suspend = s3c2410fb_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) .resume = s3c2410fb_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) .name = "s3c2410-lcd",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) static struct platform_driver s3c2412fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) .probe = s3c2412fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) .remove = s3c2410fb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) .suspend = s3c2410fb_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) .resume = s3c2410fb_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) .name = "s3c2412-lcd",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) int __init s3c2410fb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) int ret = platform_driver_register(&s3c2410fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) ret = platform_driver_register(&s3c2412fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) static void __exit s3c2410fb_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) platform_driver_unregister(&s3c2410fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) platform_driver_unregister(&s3c2412fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) module_init(s3c2410fb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) module_exit(s3c2410fb_cleanup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) MODULE_DESCRIPTION("Framebuffer driver for the s3c2410");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) MODULE_ALIAS("platform:s3c2410-lcd");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) MODULE_ALIAS("platform:s3c2412-lcd");