^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/drivers/video/ep93xx-fb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Framebuffer support for the EP93xx series.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2007 Bluewater Systems Ltd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Author: Ryan Mallon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (c) 2009 H Hartley Sweeten <hsweeten@visionengravers.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Based on the Cirrus Logic ep93xxfb driver, and various other ep93xxfb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * drivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/clk.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/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/platform_data/video-ep93xx.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* Vertical Frame Timing Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define EP93XXFB_VLINES_TOTAL 0x0000 /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define EP93XXFB_VSYNC 0x0004 /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define EP93XXFB_VACTIVE 0x0008 /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define EP93XXFB_VBLANK 0x0228 /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define EP93XXFB_VCLK 0x000c /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /* Horizontal Frame Timing Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define EP93XXFB_HCLKS_TOTAL 0x0010 /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define EP93XXFB_HSYNC 0x0014 /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define EP93XXFB_HACTIVE 0x0018 /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define EP93XXFB_HBLANK 0x022c /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define EP93XXFB_HCLK 0x001c /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* Frame Buffer Memory Configuration Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define EP93XXFB_SCREEN_PAGE 0x0028
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define EP93XXFB_SCREEN_HPAGE 0x002c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define EP93XXFB_SCREEN_LINES 0x0030
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define EP93XXFB_LINE_LENGTH 0x0034
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define EP93XXFB_VLINE_STEP 0x0038
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define EP93XXFB_LINE_CARRY 0x003c /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define EP93XXFB_EOL_OFFSET 0x0230
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* Other Video Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define EP93XXFB_BRIGHTNESS 0x0020
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define EP93XXFB_ATTRIBS 0x0024 /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define EP93XXFB_SWLOCK 0x007c /* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define EP93XXFB_AC_RATE 0x0214
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define EP93XXFB_FIFO_LEVEL 0x0234
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define EP93XXFB_PIXELMODE 0x0054
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define EP93XXFB_PIXELMODE_32BPP (0x7 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define EP93XXFB_PIXELMODE_24BPP (0x6 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define EP93XXFB_PIXELMODE_16BPP (0x4 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define EP93XXFB_PIXELMODE_8BPP (0x2 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define EP93XXFB_PIXELMODE_SHIFT_1P_24B (0x0 << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define EP93XXFB_PIXELMODE_SHIFT_1P_18B (0x1 << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define EP93XXFB_PIXELMODE_COLOR_LUT (0x0 << 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define EP93XXFB_PIXELMODE_COLOR_888 (0x4 << 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define EP93XXFB_PIXELMODE_COLOR_555 (0x5 << 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define EP93XXFB_PARL_IF_OUT 0x0058
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define EP93XXFB_PARL_IF_IN 0x005c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* Blink Control Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define EP93XXFB_BLINK_RATE 0x0040
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define EP93XXFB_BLINK_MASK 0x0044
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define EP93XXFB_BLINK_PATTRN 0x0048
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define EP93XXFB_PATTRN_MASK 0x004c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define EP93XXFB_BKGRND_OFFSET 0x0050
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* Hardware Cursor Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define EP93XXFB_CURSOR_ADR_START 0x0060
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define EP93XXFB_CURSOR_ADR_RESET 0x0064
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define EP93XXFB_CURSOR_SIZE 0x0068
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define EP93XXFB_CURSOR_COLOR1 0x006c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define EP93XXFB_CURSOR_COLOR2 0x0070
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define EP93XXFB_CURSOR_BLINK_COLOR1 0x021c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define EP93XXFB_CURSOR_BLINK_COLOR2 0x0220
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define EP93XXFB_CURSOR_XY_LOC 0x0074
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define EP93XXFB_CURSOR_DSCAN_HY_LOC 0x0078
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define EP93XXFB_CURSOR_BLINK_RATE_CTRL 0x0224
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /* LUT Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define EP93XXFB_GRY_SCL_LUTR 0x0080
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define EP93XXFB_GRY_SCL_LUTG 0x0280
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define EP93XXFB_GRY_SCL_LUTB 0x0300
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define EP93XXFB_LUT_SW_CONTROL 0x0218
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define EP93XXFB_LUT_SW_CONTROL_SWTCH (1 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define EP93XXFB_LUT_SW_CONTROL_SSTAT (1 << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define EP93XXFB_COLOR_LUT 0x0400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /* Video Signature Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #define EP93XXFB_VID_SIG_RSLT_VAL 0x0200
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #define EP93XXFB_VID_SIG_CTRL 0x0204
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #define EP93XXFB_VSIG 0x0208
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #define EP93XXFB_HSIG 0x020c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define EP93XXFB_SIG_CLR_STR 0x0210
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* Minimum / Maximum resolutions supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define EP93XXFB_MIN_XRES 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define EP93XXFB_MIN_YRES 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define EP93XXFB_MAX_XRES 1024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #define EP93XXFB_MAX_YRES 768
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct ep93xx_fbi {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct ep93xxfb_mach_info *mach_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) void __iomem *mmio_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) unsigned int pseudo_palette[256];
^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 check_screenpage_bug = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) module_param(check_screenpage_bug, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) MODULE_PARM_DESC(check_screenpage_bug,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) "Check for bit 27 screen page bug. Default = 1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static inline unsigned int ep93xxfb_readl(struct ep93xx_fbi *fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) unsigned int off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return __raw_readl(fbi->mmio_base + off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static inline void ep93xxfb_writel(struct ep93xx_fbi *fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) unsigned int val, unsigned int off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) __raw_writel(val, fbi->mmio_base + off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * Write to one of the locked raster registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static inline void ep93xxfb_out_locked(struct ep93xx_fbi *fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) unsigned int val, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * We don't need a lock or delay here since the raster register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * block will remain unlocked until the next access.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ep93xxfb_writel(fbi, 0xaa, EP93XXFB_SWLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) ep93xxfb_writel(fbi, val, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static void ep93xxfb_set_video_attribs(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) unsigned int attribs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) attribs = EP93XXFB_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) attribs |= fbi->mach_info->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) ep93xxfb_out_locked(fbi, attribs, EP93XXFB_ATTRIBS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int ep93xxfb_set_pixelmode(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) info->var.transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) info->var.transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) val = EP93XXFB_PIXELMODE_8BPP | EP93XXFB_PIXELMODE_COLOR_LUT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) EP93XXFB_PIXELMODE_SHIFT_1P_18B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) info->var.red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) info->var.red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) info->var.green.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) info->var.green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) info->var.blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) info->var.blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) val = EP93XXFB_PIXELMODE_16BPP | EP93XXFB_PIXELMODE_COLOR_555 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) EP93XXFB_PIXELMODE_SHIFT_1P_18B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) info->var.red.offset = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) info->var.red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) info->var.green.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) info->var.green.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) info->var.blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) info->var.blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) val = EP93XXFB_PIXELMODE_24BPP | EP93XXFB_PIXELMODE_COLOR_888 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) EP93XXFB_PIXELMODE_SHIFT_1P_24B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) info->var.red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) info->var.red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) info->var.green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) info->var.green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) info->var.blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) info->var.blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) val = EP93XXFB_PIXELMODE_32BPP | EP93XXFB_PIXELMODE_COLOR_888 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) EP93XXFB_PIXELMODE_SHIFT_1P_24B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) info->var.red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) info->var.red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) info->var.green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) info->var.green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) info->var.blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) info->var.blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) ep93xxfb_writel(fbi, val, EP93XXFB_PIXELMODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) static void ep93xxfb_set_timing(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) unsigned int vlines_total, hclks_total, start, stop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) vlines_total = info->var.yres + info->var.upper_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) info->var.lower_margin + info->var.vsync_len - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) hclks_total = info->var.xres + info->var.left_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) info->var.right_margin + info->var.hsync_len - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) ep93xxfb_out_locked(fbi, vlines_total, EP93XXFB_VLINES_TOTAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) ep93xxfb_out_locked(fbi, hclks_total, EP93XXFB_HCLKS_TOTAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) start = vlines_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) stop = vlines_total - info->var.vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VSYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) start = vlines_total - info->var.vsync_len - info->var.upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) stop = info->var.lower_margin - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VBLANK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VACTIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) start = vlines_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) stop = vlines_total + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VCLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) start = hclks_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) stop = hclks_total - info->var.hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HSYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) start = hclks_total - info->var.hsync_len - info->var.left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) stop = info->var.right_margin - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HBLANK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HACTIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) start = hclks_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) stop = hclks_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HCLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) ep93xxfb_out_locked(fbi, 0x0, EP93XXFB_LINE_CARRY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int ep93xxfb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) clk_set_rate(fbi->clk, 1000 * PICOS2KHZ(info->var.pixclock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) ep93xxfb_set_timing(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) info->fix.line_length = info->var.xres_virtual *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) info->var.bits_per_pixel / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) ep93xxfb_writel(fbi, info->fix.smem_start, EP93XXFB_SCREEN_PAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) ep93xxfb_writel(fbi, info->var.yres - 1, EP93XXFB_SCREEN_LINES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) ep93xxfb_writel(fbi, ((info->var.xres * info->var.bits_per_pixel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) / 32) - 1, EP93XXFB_LINE_LENGTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) ep93xxfb_writel(fbi, info->fix.line_length / 4, EP93XXFB_VLINE_STEP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) ep93xxfb_set_video_attribs(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return 0;
^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 int ep93xxfb_check_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) err = ep93xxfb_set_pixelmode(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) var->xres = max_t(unsigned int, var->xres, EP93XXFB_MIN_XRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) var->xres = min_t(unsigned int, var->xres, EP93XXFB_MAX_XRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) var->xres_virtual = max(var->xres_virtual, var->xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) var->yres = max_t(unsigned int, var->yres, EP93XXFB_MIN_YRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) var->yres = min_t(unsigned int, var->yres, EP93XXFB_MAX_YRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) var->yres_virtual = max(var->yres_virtual, var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) static int ep93xxfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) unsigned int offset = vma->vm_pgoff << PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (offset < info->fix.smem_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return dma_mmap_wc(info->dev, vma, info->screen_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) info->fix.smem_start, info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static int ep93xxfb_blank(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) unsigned int attribs = ep93xxfb_readl(fbi, EP93XXFB_ATTRIBS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (blank_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (fbi->mach_info->blank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) fbi->mach_info->blank(blank_mode, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) ep93xxfb_out_locked(fbi, attribs & ~EP93XXFB_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) EP93XXFB_ATTRIBS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) clk_disable(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) clk_enable(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) ep93xxfb_out_locked(fbi, attribs | EP93XXFB_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) EP93XXFB_ATTRIBS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (fbi->mach_info->blank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) fbi->mach_info->blank(blank_mode, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static inline int ep93xxfb_convert_color(int val, int width)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return ((val << width) + 0x7fff - val) >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) unsigned int green, unsigned int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) unsigned int transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) unsigned int *pal = info->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) unsigned int ctrl, i, rgb, lut_current, lut_stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) switch (info->fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (regno > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) rgb = ((red & 0xff00) << 8) | (green & 0xff00) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) ((blue & 0xff00) >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) pal[regno] = rgb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) ep93xxfb_writel(fbi, rgb, (EP93XXFB_COLOR_LUT + (regno << 2)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) ctrl = ep93xxfb_readl(fbi, EP93XXFB_LUT_SW_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) lut_stat = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SSTAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) lut_current = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SWTCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (lut_stat == lut_current) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) for (i = 0; i < 256; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) ep93xxfb_writel(fbi, pal[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) EP93XXFB_COLOR_LUT + (i << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) ep93xxfb_writel(fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) ctrl ^ EP93XXFB_LUT_SW_CONTROL_SWTCH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) EP93XXFB_LUT_SW_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (regno > 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) red = ep93xxfb_convert_color(red, info->var.red.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) green = ep93xxfb_convert_color(green, info->var.green.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) blue = ep93xxfb_convert_color(blue, info->var.blue.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) transp = ep93xxfb_convert_color(transp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) info->var.transp.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) pal[regno] = (red << info->var.red.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) (green << info->var.green.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) (blue << info->var.blue.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) (transp << info->var.transp.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) static const struct fb_ops ep93xxfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) .fb_check_var = ep93xxfb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) .fb_set_par = ep93xxfb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) .fb_blank = ep93xxfb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) .fb_setcolreg = ep93xxfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) .fb_mmap = ep93xxfb_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) static int ep93xxfb_alloc_videomem(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) char __iomem *virt_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) dma_addr_t phys_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) unsigned int fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) /* Maximum 16bpp -> used memory is maximum x*y*2 bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) virt_addr = dma_alloc_wc(info->dev, fb_size, &phys_addr, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (!virt_addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * There is a bug in the ep93xx framebuffer which causes problems
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) * if bit 27 of the physical address is set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) * See: https://marc.info/?l=linux-arm-kernel&m=110061245502000&w=2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) * There does not seem to be any official errata for this, but I
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) * have confirmed the problem exists on my hardware (ep9315) at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * least.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (check_screenpage_bug && phys_addr & (1 << 27)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) dev_err(info->dev, "ep93xx framebuffer bug. phys addr (0x%x) "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) "has bit 27 set: cannot init framebuffer\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) phys_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) dma_free_coherent(info->dev, fb_size, virt_addr, phys_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) info->fix.smem_start = phys_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) info->fix.smem_len = fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) info->screen_base = virt_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static void ep93xxfb_dealloc_videomem(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) if (info->screen_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) dma_free_coherent(info->dev, info->fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) info->screen_base, info->fix.smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) static int ep93xxfb_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) struct ep93xxfb_mach_info *mach_info = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) struct ep93xx_fbi *fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) char *video_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (!mach_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) info = framebuffer_alloc(sizeof(struct ep93xx_fbi), &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) info->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) platform_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) fbi->mach_info = mach_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) err = fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) goto failed_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) err = ep93xxfb_alloc_videomem(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) goto failed_videomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (!res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) err = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) goto failed_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * FIXME - We don't do a request_mem_region here because we are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) * sharing the register space with the backlight driver (see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) * drivers/video/backlight/ep93xx_bl.c) and doing so will cause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * the second loaded driver to return -EBUSY.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) * NOTE: No locking is required; the backlight does not touch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) * any of the framebuffer registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) fbi->res = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) fbi->mmio_base = devm_ioremap(&pdev->dev, res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) if (!fbi->mmio_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) err = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) goto failed_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) strcpy(info->fix.id, pdev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) info->fbops = &ep93xxfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) info->fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) info->fix.accel = FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) info->var.activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) info->var.vmode = FB_VMODE_NONINTERLACED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) info->flags = FBINFO_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) info->node = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) info->state = FBINFO_STATE_RUNNING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) info->pseudo_palette = &fbi->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) fb_get_options("ep93xx-fb", &video_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) err = fb_find_mode(&info->var, info, video_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) NULL, 0, NULL, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if (err == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) dev_err(info->dev, "No suitable video mode found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) goto failed_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (mach_info->setup) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) err = mach_info->setup(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) goto failed_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) err = ep93xxfb_check_var(&info->var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) goto failed_check;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) fbi->clk = devm_clk_get(&pdev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (IS_ERR(fbi->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) err = PTR_ERR(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) fbi->clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) goto failed_check;
^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) ep93xxfb_set_par(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) clk_enable(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) err = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) goto failed_check;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) dev_info(info->dev, "registered. Mode = %dx%d-%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) info->var.xres, info->var.yres, info->var.bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) failed_check:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (fbi->mach_info->teardown)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) fbi->mach_info->teardown(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) failed_resource:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) ep93xxfb_dealloc_videomem(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) failed_videomem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) failed_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) static int ep93xxfb_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) struct fb_info *info = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) clk_disable(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) ep93xxfb_dealloc_videomem(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) if (fbi->mach_info->teardown)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) fbi->mach_info->teardown(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) return 0;
^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 struct platform_driver ep93xxfb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) .probe = ep93xxfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) .remove = ep93xxfb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) .name = "ep93xx-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) module_platform_driver(ep93xxfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) MODULE_DESCRIPTION("EP93XX Framebuffer Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) MODULE_ALIAS("platform:ep93xx-fb");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) MODULE_AUTHOR("Ryan Mallon, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) "H Hartley Sweeten <hsweeten@visionengravers.com");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) MODULE_LICENSE("GPL");