^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Xilinx TFT frame buffer driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: MontaVista Software, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * source@mvista.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * 2002-2007 (c) MontaVista Software, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * 2007 (c) Secret Lab Technologies, Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * 2009 (c) Xilinx Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * This file is licensed under the terms of the GNU General Public License
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * version 2. This program is licensed "as is" without any warranty of any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * kind, whether express or implied.
^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * This driver was based on au1100fb.c by MontaVista rewritten for 2.6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * by Embedded Alley Solutions <source@embeddedalley.com>, which in turn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * was based on skeletonfb.c, Skeleton for a frame buffer device by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * Geert Uytterhoeven.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <asm/dcr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define DRIVER_NAME "xilinxfb"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * Xilinx calls it "TFT LCD Controller" though it can also be used for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * the VGA port on the Xilinx ML40x board. This is a hardware display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * controller for a 640x480 resolution TFT or VGA screen.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * The interface to the framebuffer is nice and simple. There are two
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * control registers. The first tells the LCD interface where in memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * the frame buffer is (only the 11 most significant bits are used, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * don't start thinking about scrolling). The second allows the LCD to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * be turned on or off as well as rotated 180 degrees.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * In case of direct BUS access the second control register will be at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * an offset of 4 as compared to the DCR access where the offset is 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * i.e. REG_CTRL. So this is taken care in the function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * xilinx_fb_out32 where it left shifts the offset 2 times in case of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * direct BUS access.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define NUM_REGS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define REG_FB_ADDR 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define REG_CTRL 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define REG_CTRL_ENABLE 0x0001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define REG_CTRL_ROTATE 0x0002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * The hardware only handles a single mode: 640x480 24 bit true
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * color. Each pixel gets a word (32 bits) of memory. Within each word,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * the 8 most significant bits are ignored, the next 8 bits are the red
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * level, the next 8 bits are the green level and the 8 least
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * significant bits are the blue level. Each row of the LCD uses 1024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * words, but only the first 640 pixels are displayed with the other 384
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * words being ignored. There are 480 rows.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define BYTES_PER_PIXEL 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define RED_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define GREEN_SHIFT 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define BLUE_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* ML300/403 reference design framebuffer driver platform data struct */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct xilinxfb_platform_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) u32 rotate_screen; /* Flag to rotate display 180 degrees */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) u32 screen_height_mm; /* Physical dimensions of screen in mm */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u32 screen_width_mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) u32 xres, yres; /* resolution of screen in pixels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u32 xvirt, yvirt; /* resolution of memory buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* Physical address of framebuffer memory; If non-zero, driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * will use provided memory address instead of allocating one from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * the consistent pool.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) u32 fb_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * Default xilinxfb configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static const struct xilinxfb_platform_data xilinx_fb_default_pdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .xres = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .yres = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .xvirt = 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .yvirt = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static const struct fb_fix_screeninfo xilinx_fb_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) .id = "Xilinx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .type = FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .visual = FB_VISUAL_TRUECOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) .accel = FB_ACCEL_NONE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static const struct fb_var_screeninfo xilinx_fb_var = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .bits_per_pixel = BITS_PER_PIXEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .red = { RED_SHIFT, 8, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .green = { GREEN_SHIFT, 8, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .blue = { BLUE_SHIFT, 8, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .transp = { 0, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .activate = FB_ACTIVATE_NOW
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) #define BUS_ACCESS_FLAG 0x1 /* 1 = BUS, 0 = DCR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #define LITTLE_ENDIAN_ACCESS 0x2 /* LITTLE ENDIAN IO functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct xilinxfb_drvdata {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct fb_info info; /* FB driver info record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) phys_addr_t regs_phys; /* phys. address of the control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) void __iomem *regs; /* virt. address of the control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) dcr_host_t dcr_host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) unsigned int dcr_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) void *fb_virt; /* virt. address of the frame buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) dma_addr_t fb_phys; /* phys. address of the frame buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) int fb_alloced; /* Flag, was the fb memory alloced? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) u8 flags; /* features of the driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) u32 reg_ctrl_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) u32 pseudo_palette[PALETTE_ENTRIES_NO];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /* Fake palette of 16 colors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #define to_xilinxfb_drvdata(_info) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) container_of(_info, struct xilinxfb_drvdata, info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * The XPS TFT Controller can be accessed through BUS or DCR interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * To perform the read/write on the registers we need to check on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * which bus its connected and call the appropriate write API.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static void xilinx_fb_out32(struct xilinxfb_drvdata *drvdata, u32 offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (drvdata->flags & BUS_ACCESS_FLAG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (drvdata->flags & LITTLE_ENDIAN_ACCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) iowrite32(val, drvdata->regs + (offset << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) iowrite32be(val, drvdata->regs + (offset << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) dcr_write(drvdata->dcr_host, offset, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static u32 xilinx_fb_in32(struct xilinxfb_drvdata *drvdata, u32 offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (drvdata->flags & BUS_ACCESS_FLAG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (drvdata->flags & LITTLE_ENDIAN_ACCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return ioread32(drvdata->regs + (offset << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) return ioread32be(drvdata->regs + (offset << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return dcr_read(drvdata->dcr_host, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) xilinx_fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) unsigned int blue, unsigned int transp, struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) u32 *palette = fbi->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (regno >= PALETTE_ENTRIES_NO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (fbi->var.grayscale) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) /* Convert color to grayscale.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * grayscale = 0.30*R + 0.59*G + 0.11*B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) blue = (red * 77 + green * 151 + blue * 28 + 127) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) green = blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) red = green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) /* fbi->fix.visual is always FB_VISUAL_TRUECOLOR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* We only handle 8 bits of each color. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) red >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) green >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) blue >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) palette[regno] = (red << RED_SHIFT) | (green << GREEN_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) (blue << BLUE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^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 int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) struct xilinxfb_drvdata *drvdata = to_xilinxfb_drvdata(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) switch (blank_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) case FB_BLANK_UNBLANK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* turn on panel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) xilinx_fb_out32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) /* turn off panel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) xilinx_fb_out32(drvdata, REG_CTRL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return 0; /* success */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static const struct fb_ops xilinxfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) .fb_setcolreg = xilinx_fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) .fb_blank = xilinx_fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) /* ---------------------------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * Bus independent setup/teardown
^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) static int xilinxfb_assign(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct xilinxfb_drvdata *drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct xilinxfb_platform_data *pdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (drvdata->flags & BUS_ACCESS_FLAG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) drvdata->regs = devm_ioremap_resource(&pdev->dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (IS_ERR(drvdata->regs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return PTR_ERR(drvdata->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) drvdata->regs_phys = res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /* Allocate the framebuffer memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (pdata->fb_phys) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) drvdata->fb_phys = pdata->fb_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) drvdata->fb_alloced = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) &drvdata->fb_phys,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (!drvdata->fb_virt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) dev_err(dev, "Could not allocate frame buffer memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) /* Clear (turn to black) the framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) /* Tell the hardware where the frame buffer is */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) rc = xilinx_fb_in32(drvdata, REG_FB_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) /* Endianness detection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (rc != drvdata->fb_phys) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) drvdata->flags |= LITTLE_ENDIAN_ACCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
^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) /* Turn on the display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (pdata->rotate_screen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) xilinx_fb_out32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) /* Fill struct fb_info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) drvdata->info.device = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) drvdata->info.fbops = &xilinxfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) drvdata->info.fix = xilinx_fb_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) drvdata->info.fix.smem_start = drvdata->fb_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) drvdata->info.fix.smem_len = fbsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) drvdata->info.pseudo_palette = drvdata->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) drvdata->info.flags = FBINFO_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) drvdata->info.var = xilinx_fb_var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) drvdata->info.var.height = pdata->screen_height_mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) drvdata->info.var.width = pdata->screen_width_mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) drvdata->info.var.xres = pdata->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) drvdata->info.var.yres = pdata->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) drvdata->info.var.xres_virtual = pdata->xvirt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) drvdata->info.var.yres_virtual = pdata->yvirt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) /* Allocate a colour map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) dev_err(dev, "Fail to allocate colormap (%d entries)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) PALETTE_ENTRIES_NO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) goto err_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) /* Register new frame buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) rc = register_framebuffer(&drvdata->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) dev_err(dev, "Could not register frame buffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) goto err_regfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (drvdata->flags & BUS_ACCESS_FLAG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) /* Put a banner in the log (for DEBUG) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) dev_dbg(dev, "regs: phys=%pa, virt=%p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) &drvdata->regs_phys, drvdata->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) /* Put a banner in the log (for DEBUG) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) (unsigned long long)drvdata->fb_phys, drvdata->fb_virt, fbsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return 0; /* success */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) err_regfb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) fb_dealloc_cmap(&drvdata->info.cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) err_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (drvdata->fb_alloced)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) drvdata->fb_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) iounmap(drvdata->fb_virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) /* Turn off the display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) xilinx_fb_out32(drvdata, REG_CTRL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) static int xilinxfb_release(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) unregister_framebuffer(&drvdata->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) fb_dealloc_cmap(&drvdata->info.cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (drvdata->fb_alloced)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) drvdata->fb_virt, drvdata->fb_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) iounmap(drvdata->fb_virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /* Turn off the display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) xilinx_fb_out32(drvdata, REG_CTRL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /* Release the resources, as allocated based on interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (!(drvdata->flags & BUS_ACCESS_FLAG))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) /* ---------------------------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) * OF bus binding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) static int xilinxfb_of_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) const u32 *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) u32 tft_access = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) struct xilinxfb_platform_data pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct xilinxfb_drvdata *drvdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) /* Copy with the default pdata (not a ptr reference!) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) pdata = xilinx_fb_default_pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) /* Allocate the driver data region */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (!drvdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return -ENOMEM;
^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) * To check whether the core is connected directly to DCR or BUS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * interface and initialize the tft_access accordingly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) of_property_read_u32(pdev->dev.of_node, "xlnx,dcr-splb-slave-if",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) &tft_access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) * Fill the resource structure if its direct BUS interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * otherwise fill the dcr_host structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (tft_access)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) drvdata->flags |= BUS_ACCESS_FLAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) int start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) start = dcr_resource_start(pdev->dev.of_node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) drvdata->dcr_len = dcr_resource_len(pdev->dev.of_node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) drvdata->dcr_host = dcr_map(pdev->dev.of_node, start, drvdata->dcr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (!DCR_MAP_OK(drvdata->dcr_host)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) dev_err(&pdev->dev, "invalid DCR address\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) prop = of_get_property(pdev->dev.of_node, "phys-size", &size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if ((prop) && (size >= sizeof(u32) * 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) pdata.screen_width_mm = prop[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) pdata.screen_height_mm = prop[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) prop = of_get_property(pdev->dev.of_node, "resolution", &size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if ((prop) && (size >= sizeof(u32) * 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) pdata.xres = prop[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) pdata.yres = prop[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) prop = of_get_property(pdev->dev.of_node, "virtual-resolution", &size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if ((prop) && (size >= sizeof(u32) * 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) pdata.xvirt = prop[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) pdata.yvirt = prop[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) if (of_find_property(pdev->dev.of_node, "rotate-display", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) pdata.rotate_screen = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) dev_set_drvdata(&pdev->dev, drvdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) return xilinxfb_assign(pdev, drvdata, &pdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) static int xilinxfb_of_remove(struct platform_device *op)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return xilinxfb_release(&op->dev);
^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) /* Match table for of_platform binding */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) static const struct of_device_id xilinxfb_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) { .compatible = "xlnx,xps-tft-1.00.a", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) { .compatible = "xlnx,xps-tft-2.00.a", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) { .compatible = "xlnx,xps-tft-2.01.a", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) { .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) { .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) static struct platform_driver xilinxfb_of_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) .probe = xilinxfb_of_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) .remove = xilinxfb_of_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) .name = DRIVER_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) .of_match_table = xilinxfb_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) module_platform_driver(xilinxfb_of_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) MODULE_LICENSE("GPL");