^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * linux/drivers/video/pxa168fb.c -- Marvell PXA168 LCD Controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2008 Marvell International Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * 2009-02-16 adapted from original version for PXA168/910
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Jun Nie <njun@marvell.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * License. See the file COPYING in the main directory of this archive for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <video/pxa168fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include "pxa168fb.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define DEFAULT_REFRESH 60 /* Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static int determine_best_pix_fmt(struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * Pseudocolor mode?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (var->bits_per_pixel == 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return PIX_FMT_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Check for 565/1555.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (var->bits_per_pixel == 16 && var->red.length <= 5 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) var->green.length <= 6 && var->blue.length <= 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (var->transp.length == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (var->red.offset >= var->blue.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return PIX_FMT_RGB565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return PIX_FMT_BGR565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (var->transp.length == 1 && var->green.length <= 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (var->red.offset >= var->blue.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return PIX_FMT_RGB1555;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return PIX_FMT_BGR1555;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * Check for 888/A888.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (var->bits_per_pixel <= 32 && var->red.length <= 8 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) var->green.length <= 8 && var->blue.length <= 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (var->bits_per_pixel == 24 && var->transp.length == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (var->red.offset >= var->blue.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return PIX_FMT_RGB888PACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return PIX_FMT_BGR888PACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (var->bits_per_pixel == 32 && var->transp.length == 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (var->red.offset >= var->blue.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return PIX_FMT_RGBA888;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return PIX_FMT_BGRA888;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (var->red.offset >= var->blue.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return PIX_FMT_RGB888UNPACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return PIX_FMT_BGR888UNPACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static void set_pix_fmt(struct fb_var_screeninfo *var, int pix_fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) switch (pix_fmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) case PIX_FMT_RGB565:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) var->bits_per_pixel = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) var->red.offset = 11; var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) var->green.offset = 5; var->green.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) var->blue.offset = 0; var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) var->transp.offset = 0; var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) case PIX_FMT_BGR565:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) var->bits_per_pixel = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) var->red.offset = 0; var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) var->green.offset = 5; var->green.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) var->blue.offset = 11; var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) var->transp.offset = 0; var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) case PIX_FMT_RGB1555:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) var->bits_per_pixel = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) var->red.offset = 10; var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) var->green.offset = 5; var->green.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) var->blue.offset = 0; var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) var->transp.offset = 15; var->transp.length = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) case PIX_FMT_BGR1555:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) var->bits_per_pixel = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) var->red.offset = 0; var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) var->green.offset = 5; var->green.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) var->blue.offset = 10; var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) var->transp.offset = 15; var->transp.length = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) case PIX_FMT_RGB888PACK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) var->bits_per_pixel = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) var->red.offset = 16; var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) var->green.offset = 8; var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) var->blue.offset = 0; var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) var->transp.offset = 0; var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) case PIX_FMT_BGR888PACK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) var->bits_per_pixel = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) var->red.offset = 0; var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) var->green.offset = 8; var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) var->blue.offset = 16; var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) var->transp.offset = 0; var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) case PIX_FMT_RGBA888:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) var->bits_per_pixel = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) var->red.offset = 16; var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) var->green.offset = 8; var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) var->blue.offset = 0; var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) var->transp.offset = 24; var->transp.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) case PIX_FMT_BGRA888:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) var->bits_per_pixel = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) var->red.offset = 0; var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) var->green.offset = 8; var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) var->blue.offset = 16; var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) var->transp.offset = 24; var->transp.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) case PIX_FMT_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) var->bits_per_pixel = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) var->red.offset = 0; var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) var->green.offset = 0; var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) var->blue.offset = 0; var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) var->transp.offset = 0; var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) static void set_mode(struct pxa168fb_info *fbi, struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct fb_videomode *mode, int pix_fmt, int ystretch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) struct fb_info *info = fbi->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) set_pix_fmt(var, pix_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) var->xres = mode->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) var->yres = mode->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) var->xres_virtual = max(var->xres, var->xres_virtual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (ystretch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) var->yres_virtual = info->fix.smem_len /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) (var->xres_virtual * (var->bits_per_pixel >> 3));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) var->yres_virtual = max(var->yres, var->yres_virtual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) var->grayscale = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) var->accel_flags = FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) var->pixclock = mode->pixclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) var->left_margin = mode->left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) var->right_margin = mode->right_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) var->upper_margin = mode->upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) var->lower_margin = mode->lower_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) var->hsync_len = mode->hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) var->vsync_len = mode->vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) var->sync = mode->sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) var->vmode = FB_VMODE_NONINTERLACED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) var->rotate = FB_ROTATE_UR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) static int pxa168fb_check_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct pxa168fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) int pix_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * Determine which pixel format we're going to use.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) pix_fmt = determine_best_pix_fmt(var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (pix_fmt < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return pix_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) set_pix_fmt(var, pix_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) fbi->pix_fmt = pix_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * Basic geometry sanity checks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (var->xoffset + var->xres > var->xres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (var->yoffset + var->yres > var->yres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (var->xres + var->right_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) var->hsync_len + var->left_margin > 2048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (var->yres + var->lower_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) var->vsync_len + var->upper_margin > 2048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * Check size of framebuffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (var->xres_virtual * var->yres_virtual *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) (var->bits_per_pixel >> 3) > info->fix.smem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^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) * The hardware clock divider has an integer and a fractional
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * stage:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * clk2 = clk_in / integer_divider
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * clk_out = clk2 * (1 - (fractional_divider >> 12))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * Calculate integer and fractional divider for given clk_in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) * and clk_out.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static void set_clock_divider(struct pxa168fb_info *fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) const struct fb_videomode *m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) int divider_int;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) int needed_pixclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) u64 div_result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) u32 x = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * Notice: The field pixclock is used by linux fb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) * is in pixel second. E.g. struct fb_videomode &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * struct fb_var_screeninfo
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * Check input values.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (!m || !m->pixclock || !m->refresh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) dev_err(fbi->dev, "Input refresh or pixclock is wrong.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * Using PLL/AXI clock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) x = 0x80000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * Calc divider according to refresh rate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) div_result = 1000000000000ll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) do_div(div_result, m->pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) needed_pixclk = (u32)div_result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) divider_int = clk_get_rate(fbi->clk) / needed_pixclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) /* check whether divisor is too small. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (divider_int < 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) dev_warn(fbi->dev, "Warning: clock source is too slow. "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) "Try smaller resolution\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) divider_int = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * Set setting to reg.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) x |= divider_int;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) writel(x, fbi->reg_base + LCD_CFG_SCLK_DIV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static void set_dma_control0(struct pxa168fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) u32 x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * Set bit to enable graphics DMA.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) x &= ~CFG_GRA_ENA_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) x |= fbi->active ? CFG_GRA_ENA(1) : CFG_GRA_ENA(0);
^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) * If we are in a pseudo-color mode, we need to enable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) * palette lookup.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) x |= 0x10000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) * Configure hardware pixel format.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) x &= ~(0xF << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) x |= (fbi->pix_fmt >> 1) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) * Check red and blue pixel swap.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) * 1. source data swap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * 2. panel output data swap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) x &= ~(1 << 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) x |= ((fbi->pix_fmt & 1) ^ (fbi->panel_rbswap)) << 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) static void set_dma_control1(struct pxa168fb_info *fbi, int sync)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) u32 x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * Configure default bits: vsync triggers DMA, gated clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) * enable, power save enable, configure alpha registers to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) * display 100% graphics, and set pixel command.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) x |= 0x2032ff81;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) * We trigger DMA on the falling edge of vsync if vsync is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) * active low, or on the rising edge if vsync is active high.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (!(sync & FB_SYNC_VERT_HIGH_ACT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) x |= 0x08000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static void set_graphics_start(struct fb_info *info, int xoffset, int yoffset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) struct pxa168fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) int pixel_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) pixel_offset = (yoffset * var->xres_virtual) + xoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) addr = fbi->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) writel(addr, fbi->reg_base + LCD_CFG_GRA_START_ADDR0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) static void set_dumb_panel_control(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) struct pxa168fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) struct pxa168fb_mach_info *mi = dev_get_platdata(fbi->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) u32 x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * Preserve enable flag.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL) & 0x00000001;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) x |= (fbi->is_blanked ? 0x7 : mi->dumb_mode) << 28;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) x |= mi->gpio_output_data << 20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) x |= mi->gpio_output_mask << 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) x |= mi->panel_rgb_reverse_lanes ? 0x00000080 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) x |= mi->invert_composite_blank ? 0x00000040 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) x |= (info->var.sync & FB_SYNC_COMP_HIGH_ACT) ? 0x00000020 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) x |= mi->invert_pix_val_ena ? 0x00000010 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) x |= (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x00000008;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) x |= (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x00000004;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) x |= mi->invert_pixclock ? 0x00000002 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) writel(x, fbi->reg_base + LCD_SPU_DUMB_CTRL);
^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) static void set_dumb_screen_dimensions(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) struct pxa168fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) struct fb_var_screeninfo *v = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) int x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) int y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) x = v->xres + v->right_margin + v->hsync_len + v->left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) y = v->yres + v->lower_margin + v->vsync_len + v->upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) writel((y << 16) | x, fbi->reg_base + LCD_SPUT_V_H_TOTAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) static int pxa168fb_set_par(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 pxa168fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) struct fb_videomode mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) u32 x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) * Set additional mode info.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) info->fix.ypanstep = var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) * Disable panel output while we setup the display.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) * Configure global panel parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) writel((var->yres << 16) | var->xres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) fbi->reg_base + LCD_SPU_V_H_ACTIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * convet var to video mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) fb_var_to_videomode(&mode, &info->var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /* Calculate clock divisor. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) set_clock_divider(fbi, &mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /* Configure dma ctrl regs. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) set_dma_control0(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) set_dma_control1(fbi, info->var.sync);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) * Configure graphics DMA parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) x = readl(fbi->reg_base + LCD_CFG_GRA_PITCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) writel(x, fbi->reg_base + LCD_CFG_GRA_PITCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) writel((var->yres << 16) | var->xres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) fbi->reg_base + LCD_SPU_GRA_HPXL_VLN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) writel((var->yres << 16) | var->xres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) fbi->reg_base + LCD_SPU_GZM_HPXL_VLN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * Configure dumb panel ctrl regs & timings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) set_dumb_panel_control(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) set_dumb_screen_dimensions(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) writel((var->left_margin << 16) | var->right_margin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) fbi->reg_base + LCD_SPU_H_PORCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) writel((var->upper_margin << 16) | var->lower_margin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) fbi->reg_base + LCD_SPU_V_PORCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) * Re-enable panel output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) static u32 to_rgb(u16 red, u16 green, u16 blue)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) red >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) green >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) blue >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return (red << 16) | (green << 8) | blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) unsigned int blue, unsigned int trans, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) struct pxa168fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (info->var.grayscale)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) red = green = blue = (19595 * red + 38470 * green +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 7471 * blue) >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) val = chan_to_field(red, &info->var.red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) val |= chan_to_field(green, &info->var.green);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) val |= chan_to_field(blue , &info->var.blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) fbi->pseudo_palette[regno] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) val = to_rgb(red, green, blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) writel(val, fbi->reg_base + LCD_SPU_SRAM_WRDAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) writel(0x8300 | regno, fbi->reg_base + LCD_SPU_SRAM_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static int pxa168fb_blank(int blank, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) struct pxa168fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) set_dumb_panel_control(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) static int pxa168fb_pan_display(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) set_graphics_start(info, var->xoffset, var->yoffset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return 0;
^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) static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) struct pxa168fb_info *fbi = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) fbi->reg_base + SPU_IRQ_ISR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) static const struct fb_ops pxa168fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) .fb_check_var = pxa168fb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) .fb_set_par = pxa168fb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) .fb_setcolreg = pxa168fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) .fb_blank = pxa168fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) .fb_pan_display = pxa168fb_pan_display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) static void pxa168fb_init_mode(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) struct pxa168fb_mach_info *mi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) struct pxa168fb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) u32 total_w, total_h, refresh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) u64 div_result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) const struct fb_videomode *m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * Set default value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) refresh = DEFAULT_REFRESH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) /* try to find best video mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) m = fb_find_best_mode(&info->var, &info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) fb_videomode_to_var(&info->var, m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) /* Init settings. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) var->xres_virtual = var->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) var->yres_virtual = info->fix.smem_len /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) (var->xres_virtual * (var->bits_per_pixel >> 3));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) dev_dbg(fbi->dev, "pxa168fb: find best mode: res = %dx%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) var->xres, var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) /* correct pixclock. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) total_w = var->xres + var->left_margin + var->right_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) var->hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) total_h = var->yres + var->upper_margin + var->lower_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) var->vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) div_result = 1000000000000ll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) do_div(div_result, total_w * total_h * refresh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) var->pixclock = (u32)div_result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) static int pxa168fb_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) struct pxa168fb_mach_info *mi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) struct fb_info *info = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) struct pxa168fb_info *fbi = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) int irq, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) mi = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) if (mi == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) dev_err(&pdev->dev, "no platform data defined\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) clk = devm_clk_get(&pdev->dev, "LCDCLK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (IS_ERR(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) dev_err(&pdev->dev, "unable to get LCDCLK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return PTR_ERR(clk);
^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) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (res == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) dev_err(&pdev->dev, "no IO memory defined\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (irq < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) dev_err(&pdev->dev, "no IRQ defined\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) if (info == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) /* Initialize private data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) fbi->info = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) fbi->clk = clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) fbi->dev = info->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) fbi->panel_rbswap = mi->panel_rbswap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) fbi->is_blanked = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) fbi->active = mi->active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) * Initialise static fb parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) info->node = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) strlcpy(info->fix.id, mi->id, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) info->fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) info->fix.type_aux = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) info->fix.xpanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) info->fix.ypanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) info->fix.ywrapstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) info->fix.mmio_start = res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) info->fix.mmio_len = resource_size(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) info->fix.accel = FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) info->fbops = &pxa168fb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) info->pseudo_palette = fbi->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * Map LCD controller registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) fbi->reg_base = devm_ioremap(&pdev->dev, res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (fbi->reg_base == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) goto failed_free_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) }
^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) * Allocate framebuffer memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) info->screen_base = dma_alloc_wc(fbi->dev, info->fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) &fbi->fb_start_dma, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) if (info->screen_base == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) goto failed_free_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) set_graphics_start(info, 0, 0);
^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) * Set video mode according to platform data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * init video mode data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) pxa168fb_init_mode(info, mi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) * Fill in sane defaults.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) ret = pxa168fb_check_var(&info->var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) goto failed_free_fbmem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) * enable controller clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) clk_prepare_enable(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) pxa168fb_set_par(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) * Configure default register values.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) fbi->reg_base + LCD_SPU_SRAM_PARA1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) * Allocate color map.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) goto failed_free_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) * Register irq handler.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) ret = devm_request_irq(&pdev->dev, irq, pxa168fb_handle_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) IRQF_SHARED, info->fix.id, fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) dev_err(&pdev->dev, "unable to request IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) goto failed_free_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) * Enable GFX interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) * Register framebuffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) ret = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) goto failed_free_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) platform_set_drvdata(pdev, fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) failed_free_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) failed_free_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) clk_disable_unprepare(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) failed_free_fbmem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) dma_free_wc(fbi->dev, info->fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) info->screen_base, fbi->fb_start_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) failed_free_info:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) static int pxa168fb_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) struct pxa168fb_info *fbi = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) unsigned int data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) if (!fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) /* disable DMA transfer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) data = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) data &= ~CFG_GRA_ENA_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) writel(data, fbi->reg_base + LCD_SPU_DMA_CTRL0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) info = fbi->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) writel(GRA_FRAME_IRQ0_ENA(0x0), fbi->reg_base + SPU_IRQ_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) if (info->cmap.len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) dma_free_wc(fbi->dev, info->fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) info->screen_base, info->fix.smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) clk_disable_unprepare(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) static struct platform_driver pxa168fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) .name = "pxa168-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) .probe = pxa168fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) .remove = pxa168fb_remove,
^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) module_platform_driver(pxa168fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) "Green Wan <gwan@marvell.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) MODULE_LICENSE("GPL");