Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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) /* linux/drivers/video/s3c-fb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    3)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    4)  * Copyright 2008 Openmoko Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    5)  * Copyright 2008-2010 Simtec Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    6)  *      Ben Dooks <ben@simtec.co.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    7)  *      http://armlinux.simtec.co.uk/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    9)  * Samsung SoC Framebuffer driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   11) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   12) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   14) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   15) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   17) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   18) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   19) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   20) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   21) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   22) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   23) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   24) #include <linux/platform_data/video_s3c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   25) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   26) #include <video/samsung_fimd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   28) /* This driver will export a number of framebuffer interfaces depending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   29)  * on the configuration passed in via the platform data. Each fb instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   30)  * maps to a hardware window. Currently there is no support for runtime
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   31)  * setting of the alpha-blending functions that each window has, so only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   32)  * window 0 is actually useful.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   33)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   34)  * Window 0 is treated specially, it is used for the basis of the LCD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   35)  * output timings and as the control for the output power-down state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   37) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   38) /* note, the previous use of <mach/regs-fb.h> to get platform specific data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   39)  * has been replaced by using the platform device name to pick the correct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   40)  * configuration data for the system.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   41) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   42) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   43) #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   44) #undef writel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   45) #define writel(v, r) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   46) 	pr_debug("%s: %08x => %p\n", __func__, (unsigned int)v, r); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   47) 	__raw_writel(v, r); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   48) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   49) #endif /* FB_S3C_DEBUG_REGWRITE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   50) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   51) /* irq_flags bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   52) #define S3C_FB_VSYNC_IRQ_EN	0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   53) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   54) #define VSYNC_TIMEOUT_MSEC 50
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   56) struct s3c_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   58) #define VALID_BPP(x) (1 << ((x) - 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   59) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   60) #define OSD_BASE(win, variant) ((variant).osd + ((win) * (variant).osd_stride))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   61) #define VIDOSD_A(win, variant) (OSD_BASE(win, variant) + 0x00)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   62) #define VIDOSD_B(win, variant) (OSD_BASE(win, variant) + 0x04)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   63) #define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   64) #define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   65) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   66) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   67)  * struct s3c_fb_variant - fb variant information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   68)  * @is_2443: Set if S3C2443/S3C2416 style hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   69)  * @nr_windows: The number of windows.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   70)  * @vidtcon: The base for the VIDTCONx registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   71)  * @wincon: The base for the WINxCON registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   72)  * @winmap: The base for the WINxMAP registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   73)  * @keycon: The abse for the WxKEYCON registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   74)  * @buf_start: Offset of buffer start registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   75)  * @buf_size: Offset of buffer size registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   76)  * @buf_end: Offset of buffer end registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   77)  * @osd: The base for the OSD registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   78)  * @palette: Address of palette memory, or 0 if none.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   79)  * @has_prtcon: Set if has PRTCON register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   80)  * @has_shadowcon: Set if has SHADOWCON register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   81)  * @has_blendcon: Set if has BLENDCON register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   82)  * @has_clksel: Set if VIDCON0 register has CLKSEL bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   83)  * @has_fixvclk: Set if VIDCON1 register has FIXVCLK bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   84)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   85) struct s3c_fb_variant {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   86) 	unsigned int	is_2443:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   87) 	unsigned short	nr_windows;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   88) 	unsigned int	vidtcon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   89) 	unsigned short	wincon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   90) 	unsigned short	winmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   91) 	unsigned short	keycon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   92) 	unsigned short	buf_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   93) 	unsigned short	buf_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   94) 	unsigned short	buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   95) 	unsigned short	osd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   96) 	unsigned short	osd_stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   97) 	unsigned short	palette[S3C_FB_MAX_WIN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   98) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   99) 	unsigned int	has_prtcon:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  100) 	unsigned int	has_shadowcon:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  101) 	unsigned int	has_blendcon:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  102) 	unsigned int	has_clksel:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  103) 	unsigned int	has_fixvclk:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  104) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  106) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  107)  * struct s3c_fb_win_variant
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  108)  * @has_osd_c: Set if has OSD C register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  109)  * @has_osd_d: Set if has OSD D register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  110)  * @has_osd_alpha: Set if can change alpha transparency for a window.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  111)  * @palette_sz: Size of palette in entries.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  112)  * @palette_16bpp: Set if palette is 16bits wide.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  113)  * @osd_size_off: If != 0, supports setting up OSD for a window; the appropriate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  114)  *                register is located at the given offset from OSD_BASE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  115)  * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  116)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  117)  * valid_bpp bit x is set if (x+1)BPP is supported.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  118)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  119) struct s3c_fb_win_variant {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  120) 	unsigned int	has_osd_c:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  121) 	unsigned int	has_osd_d:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  122) 	unsigned int	has_osd_alpha:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  123) 	unsigned int	palette_16bpp:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  124) 	unsigned short	osd_size_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  125) 	unsigned short	palette_sz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  126) 	u32		valid_bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  127) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  129) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  130)  * struct s3c_fb_driverdata - per-device type driver data for init time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  131)  * @variant: The variant information for this driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  132)  * @win: The window information for each window.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  133)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  134) struct s3c_fb_driverdata {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  135) 	struct s3c_fb_variant	variant;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  136) 	struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  137) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  138) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  139) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  140)  * struct s3c_fb_palette - palette information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  141)  * @r: Red bitfield.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  142)  * @g: Green bitfield.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  143)  * @b: Blue bitfield.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  144)  * @a: Alpha bitfield.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  145)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  146) struct s3c_fb_palette {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  147) 	struct fb_bitfield	r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  148) 	struct fb_bitfield	g;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  149) 	struct fb_bitfield	b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  150) 	struct fb_bitfield	a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  151) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  153) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  154)  * struct s3c_fb_win - per window private data for each framebuffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  155)  * @windata: The platform data supplied for the window configuration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  156)  * @parent: The hardware that this window is part of.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  157)  * @fbinfo: Pointer pack to the framebuffer info for this window.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  158)  * @varint: The variant information for this window.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  159)  * @palette_buffer: Buffer/cache to hold palette entries.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  160)  * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  161)  * @index: The window number of this window.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  162)  * @palette: The bitfields for changing r/g/b into a hardware palette entry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  163)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  164) struct s3c_fb_win {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  165) 	struct s3c_fb_pd_win	*windata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  166) 	struct s3c_fb		*parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  167) 	struct fb_info		*fbinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  168) 	struct s3c_fb_palette	 palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  169) 	struct s3c_fb_win_variant variant;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  170) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  171) 	u32			*palette_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  172) 	u32			 pseudo_palette[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  173) 	unsigned int		 index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  174) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  175) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  176) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  177)  * struct s3c_fb_vsync - vsync information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  178)  * @wait:	a queue for processes waiting for vsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  179)  * @count:	vsync interrupt count
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  180)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  181) struct s3c_fb_vsync {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  182) 	wait_queue_head_t	wait;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  183) 	unsigned int		count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  184) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  185) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  186) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  187)  * struct s3c_fb - overall hardware state of the hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  188)  * @slock: The spinlock protection for this data structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  189)  * @dev: The device that we bound to, for printing, etc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  190)  * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  191)  * @lcd_clk: The clk (sclk) feeding pixclk.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  192)  * @regs: The mapped hardware registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  193)  * @variant: Variant information for this hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  194)  * @enabled: A bitmask of enabled hardware windows.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  195)  * @output_on: Flag if the physical output is enabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  196)  * @pdata: The platform configuration data passed with the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  197)  * @windows: The hardware windows that have been claimed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  198)  * @irq_no: IRQ line number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  199)  * @irq_flags: irq flags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  200)  * @vsync_info: VSYNC-related information (count, queues...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  201)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  202) struct s3c_fb {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  203) 	spinlock_t		slock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  204) 	struct device		*dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  205) 	struct clk		*bus_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  206) 	struct clk		*lcd_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  207) 	void __iomem		*regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  208) 	struct s3c_fb_variant	 variant;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  209) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  210) 	unsigned char		 enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  211) 	bool			 output_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  212) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  213) 	struct s3c_fb_platdata	*pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  214) 	struct s3c_fb_win	*windows[S3C_FB_MAX_WIN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  215) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  216) 	int			 irq_no;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  217) 	unsigned long		 irq_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  218) 	struct s3c_fb_vsync	 vsync_info;
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  222)  * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  223)  * @win: The device window.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  224)  * @bpp: The bit depth.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  225)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  226) static bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  227) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  228) 	return win->variant.valid_bpp & VALID_BPP(bpp);
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  232)  * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  233)  * @var: The screen information to verify.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  234)  * @info: The framebuffer device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  235)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  236)  * Framebuffer layer call to verify the given information and allow us to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  237)  * update various information depending on the hardware capabilities.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  238)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  239) static int s3c_fb_check_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  240) 			    struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  242) 	struct s3c_fb_win *win = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  243) 	struct s3c_fb *sfb = win->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  244) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  245) 	dev_dbg(sfb->dev, "checking parameters\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  246) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  247) 	var->xres_virtual = max(var->xres_virtual, var->xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  248) 	var->yres_virtual = max(var->yres_virtual, var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  250) 	if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  251) 		dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  252) 			win->index, var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  253) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  254) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  255) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  256) 	/* always ensure these are zero, for drop through cases below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  257) 	var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  258) 	var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  260) 	switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  261) 	case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  262) 	case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  263) 	case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  264) 	case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  265) 		if (sfb->variant.palette[win->index] != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  266) 			/* non palletised, A:1,R:2,G:3,B:2 mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  267) 			var->red.offset		= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  268) 			var->green.offset	= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  269) 			var->blue.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  270) 			var->red.length		= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  271) 			var->green.length	= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  272) 			var->blue.length	= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  273) 			var->transp.offset	= 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  274) 			var->transp.length	= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  275) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  276) 			var->red.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  277) 			var->red.length	= var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  278) 			var->green	= var->red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  279) 			var->blue	= var->red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  280) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  281) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  283) 	case 19:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  284) 		/* 666 with one bit alpha/transparency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  285) 		var->transp.offset	= 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  286) 		var->transp.length	= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  287) 		fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  288) 	case 18:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  289) 		var->bits_per_pixel	= 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  290) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  291) 		/* 666 format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  292) 		var->red.offset		= 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  293) 		var->green.offset	= 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  294) 		var->blue.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  295) 		var->red.length		= 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  296) 		var->green.length	= 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  297) 		var->blue.length	= 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  298) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  299) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  300) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  301) 		/* 16 bpp, 565 format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  302) 		var->red.offset		= 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  303) 		var->green.offset	= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  304) 		var->blue.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  305) 		var->red.length		= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  306) 		var->green.length	= 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  307) 		var->blue.length	= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  308) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  310) 	case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  311) 	case 28:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  312) 	case 25:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  313) 		var->transp.length	= var->bits_per_pixel - 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  314) 		var->transp.offset	= 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  315) 		fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  316) 	case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  317) 		/* our 24bpp is unpacked, so 32bpp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  318) 		var->bits_per_pixel	= 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  319) 		var->red.offset		= 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  320) 		var->red.length		= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  321) 		var->green.offset	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  322) 		var->green.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  323) 		var->blue.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  324) 		var->blue.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  325) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  326) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  327) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  328) 		dev_err(sfb->dev, "invalid bpp\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  329) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  330) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  331) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  332) 	dev_dbg(sfb->dev, "%s: verified parameters\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  333) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  335) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  336) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  337)  * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  338)  * @sfb: The hardware state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  339)  * @pixclock: The pixel clock wanted, in picoseconds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  340)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  341)  * Given the specified pixel clock, work out the necessary divider to get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  342)  * close to the output frequency.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  343)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  344) static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  346) 	unsigned long clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  347) 	unsigned long long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  348) 	unsigned int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  349) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  350) 	if (sfb->variant.has_clksel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  351) 		clk = clk_get_rate(sfb->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  352) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  353) 		clk = clk_get_rate(sfb->lcd_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  354) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  355) 	tmp = (unsigned long long)clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  356) 	tmp *= pixclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  357) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  358) 	do_div(tmp, 1000000000UL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  359) 	result = (unsigned int)tmp / 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  360) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  361) 	dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  362) 		pixclk, clk, result, result ? clk / result : clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  363) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  364) 	return result;
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  368)  * s3c_fb_align_word() - align pixel count to word boundary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  369)  * @bpp: The number of bits per pixel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  370)  * @pix: The value to be aligned.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  371)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  372)  * Align the given pixel count so that it will start on an 32bit word
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  373)  * boundary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  374)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  375) static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  377) 	int pix_per_word;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  379) 	if (bpp > 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  380) 		return pix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  381) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  382) 	pix_per_word = (8 * 32) / bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  383) 	return ALIGN(pix, pix_per_word);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  385) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  386) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  387)  * vidosd_set_size() - set OSD size for a window
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  388)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  389)  * @win: the window to set OSD size for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  390)  * @size: OSD size register value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  391)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  392) static void vidosd_set_size(struct s3c_fb_win *win, u32 size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  394) 	struct s3c_fb *sfb = win->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  395) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  396) 	/* OSD can be set up if osd_size_off != 0 for this window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  397) 	if (win->variant.osd_size_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  398) 		writel(size, sfb->regs + OSD_BASE(win->index, sfb->variant)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  399) 				+ win->variant.osd_size_off);
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  403)  * vidosd_set_alpha() - set alpha transparency for a window
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  404)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  405)  * @win: the window to set OSD size for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  406)  * @alpha: alpha register value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  407)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  408) static void vidosd_set_alpha(struct s3c_fb_win *win, u32 alpha)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  409) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  410) 	struct s3c_fb *sfb = win->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  411) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  412) 	if (win->variant.has_osd_alpha)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  413) 		writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant));
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  417)  * shadow_protect_win() - disable updating values from shadow registers at vsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  418)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  419)  * @win: window to protect registers for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  420)  * @protect: 1 to protect (disable updates)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  421)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  422) static void shadow_protect_win(struct s3c_fb_win *win, bool protect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  423) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  424) 	struct s3c_fb *sfb = win->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  425) 	u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  426) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  427) 	if (protect) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  428) 		if (sfb->variant.has_prtcon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  429) 			writel(PRTCON_PROTECT, sfb->regs + PRTCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  430) 		} else if (sfb->variant.has_shadowcon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  431) 			reg = readl(sfb->regs + SHADOWCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  432) 			writel(reg | SHADOWCON_WINx_PROTECT(win->index),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  433) 				sfb->regs + SHADOWCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  434) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  435) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  436) 		if (sfb->variant.has_prtcon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  437) 			writel(0, sfb->regs + PRTCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  438) 		} else if (sfb->variant.has_shadowcon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  439) 			reg = readl(sfb->regs + SHADOWCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  440) 			writel(reg & ~SHADOWCON_WINx_PROTECT(win->index),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  441) 				sfb->regs + SHADOWCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  442) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  443) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  444) }
^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)  * s3c_fb_enable() - Set the state of the main LCD output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  448)  * @sfb: The main framebuffer state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  449)  * @enable: The state to set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  450)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  451) static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  452) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  453) 	u32 vidcon0 = readl(sfb->regs + VIDCON0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  454) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  455) 	if (enable && !sfb->output_on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  456) 		pm_runtime_get_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  457) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  458) 	if (enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  459) 		vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  460) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  461) 		/* see the note in the framebuffer datasheet about
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  462) 		 * why you cannot take both of these bits down at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  463) 		 * same time. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  464) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  465) 		if (vidcon0 & VIDCON0_ENVID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  466) 			vidcon0 |= VIDCON0_ENVID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  467) 			vidcon0 &= ~VIDCON0_ENVID_F;
^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) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  471) 	writel(vidcon0, sfb->regs + VIDCON0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  472) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  473) 	if (!enable && sfb->output_on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  474) 		pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  475) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  476) 	sfb->output_on = enable;
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  480)  * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  481)  * @info: The framebuffer to change.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  482)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  483)  * Framebuffer layer request to set a new mode for the specified framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  484)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  485) static int s3c_fb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  487) 	struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  488) 	struct s3c_fb_win *win = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  489) 	struct s3c_fb *sfb = win->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  490) 	void __iomem *regs = sfb->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  491) 	void __iomem *buf = regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  492) 	int win_no = win->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  493) 	u32 alpha = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  494) 	u32 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  495) 	u32 pagewidth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  496) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  497) 	dev_dbg(sfb->dev, "setting framebuffer parameters\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  498) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  499) 	pm_runtime_get_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  500) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  501) 	shadow_protect_win(win, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  502) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  503) 	switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  504) 	case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  505) 	case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  506) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  507) 	case 12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  508) 		info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  509) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  510) 	case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  511) 		if (win->variant.palette_sz >= 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  512) 			info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  513) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  514) 			info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  515) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  516) 	case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  517) 		info->fix.visual = FB_VISUAL_MONO01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  518) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  519) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  520) 		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  521) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  522) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  523) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  524) 	info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  525) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  526) 	info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  527) 	info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  528) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  529) 	/* disable the window whilst we update it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  530) 	writel(0, regs + WINCON(win_no));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  531) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  532) 	if (!sfb->output_on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  533) 		s3c_fb_enable(sfb, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  534) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  535) 	/* write the buffer address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  536) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  537) 	/* start and end registers stride is 8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  538) 	buf = regs + win_no * 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  539) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  540) 	writel(info->fix.smem_start, buf + sfb->variant.buf_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  541) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  542) 	data = info->fix.smem_start + info->fix.line_length * var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  543) 	writel(data, buf + sfb->variant.buf_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  544) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  545) 	pagewidth = (var->xres * var->bits_per_pixel) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  546) 	data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  547) 	       VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  548) 	       VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  549) 	       VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  550) 	writel(data, regs + sfb->variant.buf_size + (win_no * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  551) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  552) 	/* write 'OSD' registers to control position of framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  553) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  554) 	data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  555) 	       VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  556) 	writel(data, regs + VIDOSD_A(win_no, sfb->variant));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  557) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  558) 	data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  559) 						     var->xres - 1)) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  560) 	       VIDOSDxB_BOTRIGHT_Y(var->yres - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  561) 	       VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  562) 						     var->xres - 1)) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  563) 	       VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  564) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  565) 	writel(data, regs + VIDOSD_B(win_no, sfb->variant));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  566) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  567) 	data = var->xres * var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  568) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  569) 	alpha = VIDISD14C_ALPHA1_R(0xf) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  570) 		VIDISD14C_ALPHA1_G(0xf) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  571) 		VIDISD14C_ALPHA1_B(0xf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  572) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  573) 	vidosd_set_alpha(win, alpha);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  574) 	vidosd_set_size(win, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  575) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  576) 	/* Enable DMA channel for this window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  577) 	if (sfb->variant.has_shadowcon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  578) 		data = readl(sfb->regs + SHADOWCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  579) 		data |= SHADOWCON_CHx_ENABLE(win_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  580) 		writel(data, sfb->regs + SHADOWCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  581) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  582) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  583) 	data = WINCONx_ENWIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  584) 	sfb->enabled |= (1 << win->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  585) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  586) 	/* note, since we have to round up the bits-per-pixel, we end up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  587) 	 * relying on the bitfield information for r/g/b/a to work out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  588) 	 * exactly which mode of operation is intended. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  589) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  590) 	switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  591) 	case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  592) 		data |= WINCON0_BPPMODE_1BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  593) 		data |= WINCONx_BITSWP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  594) 		data |= WINCONx_BURSTLEN_4WORD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  595) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  596) 	case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  597) 		data |= WINCON0_BPPMODE_2BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  598) 		data |= WINCONx_BITSWP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  599) 		data |= WINCONx_BURSTLEN_8WORD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  600) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  601) 	case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  602) 		data |= WINCON0_BPPMODE_4BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  603) 		data |= WINCONx_BITSWP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  604) 		data |= WINCONx_BURSTLEN_8WORD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  605) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  606) 	case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  607) 		if (var->transp.length != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  608) 			data |= WINCON1_BPPMODE_8BPP_1232;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  609) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  610) 			data |= WINCON0_BPPMODE_8BPP_PALETTE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  611) 		data |= WINCONx_BURSTLEN_8WORD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  612) 		data |= WINCONx_BYTSWP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  613) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  614) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  615) 		if (var->transp.length != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  616) 			data |= WINCON1_BPPMODE_16BPP_A1555;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  617) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  618) 			data |= WINCON0_BPPMODE_16BPP_565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  619) 		data |= WINCONx_HAWSWP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  620) 		data |= WINCONx_BURSTLEN_16WORD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  621) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  622) 	case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  623) 	case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  624) 		if (var->red.length == 6) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  625) 			if (var->transp.length != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  626) 				data |= WINCON1_BPPMODE_19BPP_A1666;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  627) 			else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  628) 				data |= WINCON1_BPPMODE_18BPP_666;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  629) 		} else if (var->transp.length == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  630) 			data |= WINCON1_BPPMODE_25BPP_A1888
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  631) 				| WINCON1_BLD_PIX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  632) 		else if ((var->transp.length == 4) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  633) 			(var->transp.length == 8))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  634) 			data |= WINCON1_BPPMODE_28BPP_A4888
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  635) 				| WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  636) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  637) 			data |= WINCON0_BPPMODE_24BPP_888;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  638) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  639) 		data |= WINCONx_WSWP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  640) 		data |= WINCONx_BURSTLEN_16WORD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  641) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  642) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  643) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  644) 	/* Enable the colour keying for the window below this one */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  645) 	if (win_no > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  646) 		u32 keycon0_data = 0, keycon1_data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  647) 		void __iomem *keycon = regs + sfb->variant.keycon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  648) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  649) 		keycon0_data = ~(WxKEYCON0_KEYBL_EN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  650) 				WxKEYCON0_KEYEN_F |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  651) 				WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  652) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  653) 		keycon1_data = WxKEYCON1_COLVAL(0xffffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  654) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  655) 		keycon += (win_no - 1) * 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  656) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  657) 		writel(keycon0_data, keycon + WKEYCON0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  658) 		writel(keycon1_data, keycon + WKEYCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  659) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  660) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  661) 	writel(data, regs + sfb->variant.wincon + (win_no * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  662) 	writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  663) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  664) 	/* Set alpha value width */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  665) 	if (sfb->variant.has_blendcon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  666) 		data = readl(sfb->regs + BLENDCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  667) 		data &= ~BLENDCON_NEW_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  668) 		if (var->transp.length > 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  669) 			data |= BLENDCON_NEW_8BIT_ALPHA_VALUE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  670) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  671) 			data |= BLENDCON_NEW_4BIT_ALPHA_VALUE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  672) 		writel(data, sfb->regs + BLENDCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  673) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  674) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  675) 	shadow_protect_win(win, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  676) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  677) 	pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  678) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  679) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  681) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  682) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  683)  * s3c_fb_update_palette() - set or schedule a palette update.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  684)  * @sfb: The hardware information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  685)  * @win: The window being updated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  686)  * @reg: The palette index being changed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  687)  * @value: The computed palette value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  688)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  689)  * Change the value of a palette register, either by directly writing to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  690)  * the palette (this requires the palette RAM to be disconnected from the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  691)  * hardware whilst this is in progress) or schedule the update for later.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  692)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  693)  * At the moment, since we have no VSYNC interrupt support, we simply set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  694)  * the palette entry directly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  695)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  696) static void s3c_fb_update_palette(struct s3c_fb *sfb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  697) 				  struct s3c_fb_win *win,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  698) 				  unsigned int reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  699) 				  u32 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  700) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  701) 	void __iomem *palreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  702) 	u32 palcon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  703) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  704) 	palreg = sfb->regs + sfb->variant.palette[win->index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  705) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  706) 	dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  707) 		__func__, win->index, reg, palreg, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  708) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  709) 	win->palette_buffer[reg] = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  710) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  711) 	palcon = readl(sfb->regs + WPALCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  712) 	writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  713) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  714) 	if (win->variant.palette_16bpp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  715) 		writew(value, palreg + (reg * 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  716) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  717) 		writel(value, palreg + (reg * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  718) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  719) 	writel(palcon, sfb->regs + WPALCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  720) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  721) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  722) static inline unsigned int chan_to_field(unsigned int chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  723) 					 struct fb_bitfield *bf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  724) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  725) 	chan &= 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  726) 	chan >>= 16 - bf->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  727) 	return chan << bf->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  729) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  730) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  731)  * s3c_fb_setcolreg() - framebuffer layer request to change palette.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  732)  * @regno: The palette index to change.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  733)  * @red: The red field for the palette data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  734)  * @green: The green field for the palette data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  735)  * @blue: The blue field for the palette data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  736)  * @trans: The transparency (alpha) field for the palette data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  737)  * @info: The framebuffer being changed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  738)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  739) static int s3c_fb_setcolreg(unsigned regno,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  740) 			    unsigned red, unsigned green, unsigned blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  741) 			    unsigned transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  742) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  743) 	struct s3c_fb_win *win = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  744) 	struct s3c_fb *sfb = win->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  745) 	unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  746) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  747) 	dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  748) 		__func__, win->index, regno, red, green, blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  749) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  750) 	pm_runtime_get_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  751) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  752) 	switch (info->fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  753) 	case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  754) 		/* true-colour, use pseudo-palette */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  755) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  756) 		if (regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  757) 			u32 *pal = info->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  758) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  759) 			val  = chan_to_field(red,   &info->var.red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  760) 			val |= chan_to_field(green, &info->var.green);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  761) 			val |= chan_to_field(blue,  &info->var.blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  762) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  763) 			pal[regno] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  764) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  765) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  766) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  767) 	case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  768) 		if (regno < win->variant.palette_sz) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  769) 			val  = chan_to_field(red, &win->palette.r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  770) 			val |= chan_to_field(green, &win->palette.g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  771) 			val |= chan_to_field(blue, &win->palette.b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  772) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  773) 			s3c_fb_update_palette(sfb, win, regno, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  774) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  775) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  776) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  777) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  778) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  779) 		pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  780) 		return 1;	/* unknown type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  781) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  782) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  783) 	pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  784) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  786) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  787) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  788)  * s3c_fb_blank() - blank or unblank the given window
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  789)  * @blank_mode: The blank state from FB_BLANK_*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  790)  * @info: The framebuffer to blank.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  791)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  792)  * Framebuffer layer request to change the power state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  793)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  794) static int s3c_fb_blank(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  795) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  796) 	struct s3c_fb_win *win = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  797) 	struct s3c_fb *sfb = win->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  798) 	unsigned int index = win->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  799) 	u32 wincon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  800) 	u32 output_on = sfb->output_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  801) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  802) 	dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  803) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  804) 	pm_runtime_get_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  805) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  806) 	wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  807) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  808) 	switch (blank_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  809) 	case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  810) 		wincon &= ~WINCONx_ENWIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  811) 		sfb->enabled &= ~(1 << index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  812) 		fallthrough;	/* to FB_BLANK_NORMAL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  813) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  814) 	case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  815) 		/* disable the DMA and display 0x0 (black) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  816) 		shadow_protect_win(win, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  817) 		writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  818) 		       sfb->regs + sfb->variant.winmap + (index * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  819) 		shadow_protect_win(win, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  820) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  821) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  822) 	case FB_BLANK_UNBLANK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  823) 		shadow_protect_win(win, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  824) 		writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  825) 		shadow_protect_win(win, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  826) 		wincon |= WINCONx_ENWIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  827) 		sfb->enabled |= (1 << index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  828) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  829) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  830) 	case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  831) 	case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  832) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  833) 		pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  834) 		return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  835) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  836) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  837) 	shadow_protect_win(win, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  838) 	writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  839) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  840) 	/* Check the enabled state to see if we need to be running the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  841) 	 * main LCD interface, as if there are no active windows then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  842) 	 * it is highly likely that we also do not need to output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  843) 	 * anything.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  844) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  845) 	s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  846) 	shadow_protect_win(win, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  847) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  848) 	pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  849) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  850) 	return output_on == sfb->output_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  851) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  852) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  853) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  854)  * s3c_fb_pan_display() - Pan the display.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  855)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  856)  * Note that the offsets can be written to the device at any time, as their
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  857)  * values are latched at each vsync automatically. This also means that only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  858)  * the last call to this function will have any effect on next vsync, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  859)  * there is no need to sleep waiting for it to prevent tearing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  860)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  861)  * @var: The screen information to verify.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  862)  * @info: The framebuffer device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  863)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  864) static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  865) 			      struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  866) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  867) 	struct s3c_fb_win *win	= info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  868) 	struct s3c_fb *sfb	= win->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  869) 	void __iomem *buf	= sfb->regs + win->index * 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  870) 	unsigned int start_boff, end_boff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  871) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  872) 	pm_runtime_get_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  873) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  874) 	/* Offset in bytes to the start of the displayed area */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  875) 	start_boff = var->yoffset * info->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  876) 	/* X offset depends on the current bpp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  877) 	if (info->var.bits_per_pixel >= 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  878) 		start_boff += var->xoffset * (info->var.bits_per_pixel >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  879) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  880) 		switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  881) 		case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  882) 			start_boff += var->xoffset >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  883) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  884) 		case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  885) 			start_boff += var->xoffset >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  886) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  887) 		case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  888) 			start_boff += var->xoffset >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  889) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  890) 		default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  891) 			dev_err(sfb->dev, "invalid bpp\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  892) 			pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  893) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  894) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  895) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  896) 	/* Offset in bytes to the end of the displayed area */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  897) 	end_boff = start_boff + info->var.yres * info->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  898) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  899) 	/* Temporarily turn off per-vsync update from shadow registers until
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  900) 	 * both start and end addresses are updated to prevent corruption */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  901) 	shadow_protect_win(win, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  902) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  903) 	writel(info->fix.smem_start + start_boff, buf + sfb->variant.buf_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  904) 	writel(info->fix.smem_start + end_boff, buf + sfb->variant.buf_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  905) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  906) 	shadow_protect_win(win, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  907) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  908) 	pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  909) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  910) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  911) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  912) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  913)  * s3c_fb_enable_irq() - enable framebuffer interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  914)  * @sfb: main hardware state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  915)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  916) static void s3c_fb_enable_irq(struct s3c_fb *sfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  917) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  918) 	void __iomem *regs = sfb->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  919) 	u32 irq_ctrl_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  920) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  921) 	if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  922) 		/* IRQ disabled, enable it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  923) 		irq_ctrl_reg = readl(regs + VIDINTCON0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  924) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  925) 		irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  926) 		irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  927) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  928) 		irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  929) 		irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  930) 		irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  931) 		irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  932) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  933) 		writel(irq_ctrl_reg, regs + VIDINTCON0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  934) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  935) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  936) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  937) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  938)  * s3c_fb_disable_irq() - disable framebuffer interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  939)  * @sfb: main hardware state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  940)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  941) static void s3c_fb_disable_irq(struct s3c_fb *sfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  942) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  943) 	void __iomem *regs = sfb->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  944) 	u32 irq_ctrl_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  945) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  946) 	if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  947) 		/* IRQ enabled, disable it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  948) 		irq_ctrl_reg = readl(regs + VIDINTCON0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  949) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  950) 		irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  951) 		irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  952) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  953) 		writel(irq_ctrl_reg, regs + VIDINTCON0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  954) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  956) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  957) static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  958) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  959) 	struct s3c_fb *sfb = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  960) 	void __iomem  *regs = sfb->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  961) 	u32 irq_sts_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  962) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  963) 	spin_lock(&sfb->slock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  964) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  965) 	irq_sts_reg = readl(regs + VIDINTCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  966) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  967) 	if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  968) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  969) 		/* VSYNC interrupt, accept it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  970) 		writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  971) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  972) 		sfb->vsync_info.count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  973) 		wake_up_interruptible(&sfb->vsync_info.wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  974) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  975) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  976) 	/* We only support waiting for VSYNC for now, so it's safe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  977) 	 * to always disable irqs here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  978) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  979) 	s3c_fb_disable_irq(sfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  980) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  981) 	spin_unlock(&sfb->slock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  982) 	return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  983) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  984) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  985) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  986)  * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  987)  * @sfb: main hardware state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  988)  * @crtc: head index.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  989)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  990) static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  991) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  992) 	unsigned long count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  993) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  994) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  995) 	if (crtc != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  996) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  997) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  998) 	pm_runtime_get_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  999) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) 	count = sfb->vsync_info.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) 	s3c_fb_enable_irq(sfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) 	ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) 				       count != sfb->vsync_info.count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) 				       msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) 	pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) 	if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) 		return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) 			unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) 	struct s3c_fb_win *win = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) 	struct s3c_fb *sfb = win->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) 	u32 crtc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) 	switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) 	case FBIO_WAITFORVSYNC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) 		if (get_user(crtc, (u32 __user *)arg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) 			ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) 		ret = s3c_fb_wait_for_vsync(sfb, crtc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) 		ret = -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) static const struct fb_ops s3c_fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) 	.owner		= THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) 	.fb_check_var	= s3c_fb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) 	.fb_set_par	= s3c_fb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) 	.fb_blank	= s3c_fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) 	.fb_setcolreg	= s3c_fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) 	.fb_fillrect	= cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) 	.fb_copyarea	= cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) 	.fb_imageblit	= cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) 	.fb_pan_display	= s3c_fb_pan_display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) 	.fb_ioctl	= s3c_fb_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)  * s3c_fb_missing_pixclock() - calculates pixel clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053)  * @mode: The video mode to change.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055)  * Calculate the pixel clock when none has been given through platform data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) static void s3c_fb_missing_pixclock(struct fb_videomode *mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) 	u64 pixclk = 1000000000000ULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) 	u32 div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) 	div  = mode->left_margin + mode->hsync_len + mode->right_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) 	       mode->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) 	div *= mode->upper_margin + mode->vsync_len + mode->lower_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) 	       mode->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) 	div *= mode->refresh ? : 60;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) 	do_div(pixclk, div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) 	mode->pixclock = pixclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)  * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075)  * @sfb: The base resources for the hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076)  * @win: The window to initialise memory for.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)  * Allocate memory for the given framebuffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) static int s3c_fb_alloc_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) 	struct s3c_fb_pd_win *windata = win->windata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) 	unsigned int real_size, virt_size, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) 	struct fb_info *fbi = win->fbinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) 	dma_addr_t map_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) 	dev_dbg(sfb->dev, "allocating memory for display\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) 	real_size = windata->xres * windata->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) 	virt_size = windata->virtual_x * windata->virtual_y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) 	dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) 		real_size, windata->xres, windata->yres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) 		virt_size, windata->virtual_x, windata->virtual_y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) 	size = (real_size > virt_size) ? real_size : virt_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) 	size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) 	size /= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) 	fbi->fix.smem_len = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) 	size = PAGE_ALIGN(size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) 	dev_dbg(sfb->dev, "want %u bytes for window\n", size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) 	fbi->screen_buffer = dma_alloc_wc(sfb->dev, size, &map_dma, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) 	if (!fbi->screen_buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) 	dev_dbg(sfb->dev, "mapped %x to %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) 		(unsigned int)map_dma, fbi->screen_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) 	memset(fbi->screen_buffer, 0x0, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) 	fbi->fix.smem_start = map_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119)  * s3c_fb_free_memory() - free the display memory for the given window
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120)  * @sfb: The base resources for the hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)  * @win: The window to free the display memory for.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123)  * Free the display memory allocated by s3c_fb_alloc_memory().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) 	struct fb_info *fbi = win->fbinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) 	if (fbi->screen_buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) 		dma_free_wc(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) 			    fbi->screen_buffer, fbi->fix.smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135)  * s3c_fb_release_win() - release resources for a framebuffer window.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)  * @win: The window to cleanup the resources for.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138)  * Release the resources that where claimed for the hardware window,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139)  * such as the framebuffer instance and any memory claimed for it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) 	u32 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) 	if (win->fbinfo) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) 		if (sfb->variant.has_shadowcon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) 			data = readl(sfb->regs + SHADOWCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) 			data &= ~SHADOWCON_CHx_ENABLE(win->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) 			data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) 			writel(data, sfb->regs + SHADOWCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) 		unregister_framebuffer(win->fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) 		if (win->fbinfo->cmap.len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) 			fb_dealloc_cmap(&win->fbinfo->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) 		s3c_fb_free_memory(sfb, win);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) 		framebuffer_release(win->fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)  * s3c_fb_probe_win() - register an hardware window
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162)  * @sfb: The base resources for the hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)  * @variant: The variant information for this window.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164)  * @res: Pointer to where to place the resultant window.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166)  * Allocate and do the basic initialisation for one of the hardware's graphics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167)  * windows.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) static int s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) 			    struct s3c_fb_win_variant *variant,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) 			    struct s3c_fb_win **res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) 	struct fb_var_screeninfo *var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) 	struct fb_videomode initmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) 	struct s3c_fb_pd_win *windata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) 	struct s3c_fb_win *win;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) 	struct fb_info *fbinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) 	int palette_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) 	dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) 	init_waitqueue_head(&sfb->vsync_info.wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) 	palette_size = variant->palette_sz * 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) 	fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) 				   palette_size * sizeof(u32), sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) 	if (!fbinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) 	windata = sfb->pdata->win[win_no];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) 	initmode = *sfb->pdata->vtiming;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) 	WARN_ON(windata->max_bpp == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) 	WARN_ON(windata->xres == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) 	WARN_ON(windata->yres == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) 	win = fbinfo->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) 	*res = win;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) 	var = &fbinfo->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) 	win->variant = *variant;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) 	win->fbinfo = fbinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) 	win->parent = sfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) 	win->windata = windata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) 	win->index = win_no;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) 	win->palette_buffer = (u32 *)(win + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) 	ret = s3c_fb_alloc_memory(sfb, win);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) 		dev_err(sfb->dev, "failed to allocate display memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) 	/* setup the r/b/g positions for the window's palette */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) 	if (win->variant.palette_16bpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) 		/* Set RGB 5:6:5 as default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) 		win->palette.r.offset = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) 		win->palette.r.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) 		win->palette.g.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) 		win->palette.g.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) 		win->palette.b.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) 		win->palette.b.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) 		/* Set 8bpp or 8bpp and 1bit alpha */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) 		win->palette.r.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) 		win->palette.r.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) 		win->palette.g.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) 		win->palette.g.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) 		win->palette.b.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) 		win->palette.b.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) 	/* setup the initial video mode from the window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) 	initmode.xres = windata->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) 	initmode.yres = windata->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) 	fb_videomode_to_var(&fbinfo->var, &initmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) 	fbinfo->fix.type	= FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) 	fbinfo->fix.accel	= FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) 	fbinfo->var.activate	= FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) 	fbinfo->var.vmode	= FB_VMODE_NONINTERLACED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) 	fbinfo->var.bits_per_pixel = windata->default_bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) 	fbinfo->fbops		= &s3c_fb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) 	fbinfo->flags		= FBINFO_FLAG_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) 	fbinfo->pseudo_palette  = &win->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) 	/* prepare to actually start the framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) 	ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) 	if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) 		dev_err(sfb->dev, "check_var failed on initial video params\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) 	/* create initial colour map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) 	ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) 	if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) 		fb_set_cmap(&fbinfo->cmap, fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) 		dev_err(sfb->dev, "failed to allocate fb cmap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) 	s3c_fb_set_par(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) 	dev_dbg(sfb->dev, "about to register framebuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) 	/* run the check_var and set_par on our configuration. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) 	ret = register_framebuffer(fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) 	if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) 		dev_err(sfb->dev, "failed to register framebuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) 	dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283)  * s3c_fb_set_rgb_timing() - set video timing for rgb interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284)  * @sfb: The base resources for the hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286)  * Set horizontal and vertical lcd rgb interface timing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) static void s3c_fb_set_rgb_timing(struct s3c_fb *sfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) 	struct fb_videomode *vmode = sfb->pdata->vtiming;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) 	void __iomem *regs = sfb->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) 	int clkdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) 	u32 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) 	if (!vmode->pixclock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) 		s3c_fb_missing_pixclock(vmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) 	clkdiv = s3c_fb_calc_pixclk(sfb, vmode->pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) 	data = sfb->pdata->vidcon0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) 	data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) 	if (clkdiv > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) 		data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) 		data &= ~VIDCON0_CLKDIR;	/* 1:1 clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) 	if (sfb->variant.is_2443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) 		data |= (1 << 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) 	writel(data, regs + VIDCON0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) 	data = VIDTCON0_VBPD(vmode->upper_margin - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) 	       VIDTCON0_VFPD(vmode->lower_margin - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) 	       VIDTCON0_VSPW(vmode->vsync_len - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) 	writel(data, regs + sfb->variant.vidtcon);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) 	data = VIDTCON1_HBPD(vmode->left_margin - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) 	       VIDTCON1_HFPD(vmode->right_margin - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) 	       VIDTCON1_HSPW(vmode->hsync_len - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) 	writel(data, regs + sfb->variant.vidtcon + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) 	data = VIDTCON2_LINEVAL(vmode->yres - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) 	       VIDTCON2_HOZVAL(vmode->xres - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) 	       VIDTCON2_LINEVAL_E(vmode->yres - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) 	       VIDTCON2_HOZVAL_E(vmode->xres - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) 	writel(data, regs + sfb->variant.vidtcon + 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330)  * s3c_fb_clear_win() - clear hardware window registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331)  * @sfb: The base resources for the hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332)  * @win: The window to process.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334)  * Reset the specific window registers to a known state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) 	void __iomem *regs = sfb->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) 	u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) 	writel(0, regs + sfb->variant.wincon + (win * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) 	writel(0, regs + VIDOSD_A(win, sfb->variant));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) 	writel(0, regs + VIDOSD_B(win, sfb->variant));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) 	writel(0, regs + VIDOSD_C(win, sfb->variant));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) 	if (sfb->variant.has_shadowcon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) 		reg = readl(sfb->regs + SHADOWCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) 		reg &= ~(SHADOWCON_WINx_PROTECT(win) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) 			SHADOWCON_CHx_ENABLE(win) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) 			SHADOWCON_CHx_LOCAL_ENABLE(win));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) 		writel(reg, sfb->regs + SHADOWCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) static int s3c_fb_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) 	const struct platform_device_id *platid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) 	struct s3c_fb_driverdata *fbdrv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) 	struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) 	struct s3c_fb_platdata *pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) 	struct s3c_fb *sfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) 	struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) 	int win;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) 	u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) 	platid = platform_get_device_id(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) 	fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) 	if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) 		dev_err(dev, "too many windows, cannot attach\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) 	pd = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) 	if (!pd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) 		dev_err(dev, "no platform data specified\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) 	sfb = devm_kzalloc(dev, sizeof(*sfb), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) 	if (!sfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) 	dev_dbg(dev, "allocate new framebuffer %p\n", sfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) 	sfb->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) 	sfb->pdata = pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) 	sfb->variant = fbdrv->variant;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) 	spin_lock_init(&sfb->slock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) 	sfb->bus_clk = devm_clk_get(dev, "lcd");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) 	if (IS_ERR(sfb->bus_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) 		dev_err(dev, "failed to get bus clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) 		return PTR_ERR(sfb->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) 	clk_prepare_enable(sfb->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) 	if (!sfb->variant.has_clksel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) 		sfb->lcd_clk = devm_clk_get(dev, "sclk_fimd");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) 		if (IS_ERR(sfb->lcd_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) 			dev_err(dev, "failed to get lcd clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) 			ret = PTR_ERR(sfb->lcd_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) 			goto err_bus_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) 		clk_prepare_enable(sfb->lcd_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) 	pm_runtime_enable(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) 	sfb->regs = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) 	if (IS_ERR(sfb->regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) 		ret = PTR_ERR(sfb->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) 		goto err_lcd_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) 	if (!res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) 		dev_err(dev, "failed to acquire irq resource\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) 		ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) 		goto err_lcd_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) 	sfb->irq_no = res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) 	ret = devm_request_irq(dev, sfb->irq_no, s3c_fb_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) 			  0, "s3c_fb", sfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) 		dev_err(dev, "irq request failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) 		goto err_lcd_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) 	dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) 	platform_set_drvdata(pdev, sfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) 	pm_runtime_get_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) 	/* setup gpio and output polarity controls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) 	pd->setup_gpio();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) 	writel(pd->vidcon1, sfb->regs + VIDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) 	/* set video clock running at under-run */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) 	if (sfb->variant.has_fixvclk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) 		reg = readl(sfb->regs + VIDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) 		reg &= ~VIDCON1_VCLK_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) 		reg |= VIDCON1_VCLK_RUN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) 		writel(reg, sfb->regs + VIDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) 	/* zero all windows before we do anything */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) 	for (win = 0; win < fbdrv->variant.nr_windows; win++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) 		s3c_fb_clear_win(sfb, win);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) 	/* initialise colour key controls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) 	for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) 		void __iomem *regs = sfb->regs + sfb->variant.keycon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) 		regs += (win * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) 		writel(0xffffff, regs + WKEYCON0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) 		writel(0xffffff, regs + WKEYCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) 	s3c_fb_set_rgb_timing(sfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) 	/* we have the register setup, start allocating framebuffers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) 	for (win = 0; win < fbdrv->variant.nr_windows; win++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) 		if (!pd->win[win])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) 		ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) 				       &sfb->windows[win]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) 		if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) 			dev_err(dev, "failed to create window %d\n", win);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) 			for (; win >= 0; win--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) 				s3c_fb_release_win(sfb, sfb->windows[win]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) 			goto err_pm_runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) 	platform_set_drvdata(pdev, sfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) 	pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) err_pm_runtime:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) 	pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) err_lcd_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) 	pm_runtime_disable(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) 	if (!sfb->variant.has_clksel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) 		clk_disable_unprepare(sfb->lcd_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) err_bus_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) 	clk_disable_unprepare(sfb->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506)  * s3c_fb_remove() - Cleanup on module finalisation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507)  * @pdev: The platform device we are bound to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509)  * Shutdown and then release all the resources that the driver allocated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510)  * on initialisation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) static int s3c_fb_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) 	struct s3c_fb *sfb = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) 	int win;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) 	pm_runtime_get_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) 	for (win = 0; win < S3C_FB_MAX_WIN; win++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) 		if (sfb->windows[win])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) 			s3c_fb_release_win(sfb, sfb->windows[win]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) 	if (!sfb->variant.has_clksel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) 		clk_disable_unprepare(sfb->lcd_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) 	clk_disable_unprepare(sfb->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) 	pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) 	pm_runtime_disable(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) static int s3c_fb_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) 	struct s3c_fb *sfb = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) 	struct s3c_fb_win *win;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) 	int win_no;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) 	pm_runtime_get_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) 	for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) 		win = sfb->windows[win_no];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) 		if (!win)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) 		/* use the blank function to push into power-down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) 		s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) 	if (!sfb->variant.has_clksel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) 		clk_disable_unprepare(sfb->lcd_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) 	clk_disable_unprepare(sfb->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) 	pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) static int s3c_fb_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) 	struct s3c_fb *sfb = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) 	struct s3c_fb_platdata *pd = sfb->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) 	struct s3c_fb_win *win;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) 	int win_no;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) 	u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) 	pm_runtime_get_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) 	clk_prepare_enable(sfb->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) 	if (!sfb->variant.has_clksel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) 		clk_prepare_enable(sfb->lcd_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) 	/* setup gpio and output polarity controls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) 	pd->setup_gpio();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) 	writel(pd->vidcon1, sfb->regs + VIDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) 	/* set video clock running at under-run */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) 	if (sfb->variant.has_fixvclk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) 		reg = readl(sfb->regs + VIDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) 		reg &= ~VIDCON1_VCLK_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) 		reg |= VIDCON1_VCLK_RUN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) 		writel(reg, sfb->regs + VIDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) 	/* zero all windows before we do anything */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) 	for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) 		s3c_fb_clear_win(sfb, win_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) 	for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) 		void __iomem *regs = sfb->regs + sfb->variant.keycon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) 		win = sfb->windows[win_no];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) 		if (!win)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) 		shadow_protect_win(win, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) 		regs += (win_no * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) 		writel(0xffffff, regs + WKEYCON0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) 		writel(0xffffff, regs + WKEYCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) 		shadow_protect_win(win, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) 	s3c_fb_set_rgb_timing(sfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) 	/* restore framebuffers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) 	for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) 		win = sfb->windows[win_no];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) 		if (!win)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) 		dev_dbg(dev, "resuming window %d\n", win_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) 		s3c_fb_set_par(win->fbinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) 	pm_runtime_put_sync(sfb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) static int s3c_fb_runtime_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) 	struct s3c_fb *sfb = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) 	if (!sfb->variant.has_clksel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) 		clk_disable_unprepare(sfb->lcd_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) 	clk_disable_unprepare(sfb->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) static int s3c_fb_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) 	struct s3c_fb *sfb = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) 	struct s3c_fb_platdata *pd = sfb->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) 	clk_prepare_enable(sfb->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) 	if (!sfb->variant.has_clksel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) 		clk_prepare_enable(sfb->lcd_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) 	/* setup gpio and output polarity controls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) 	pd->setup_gpio();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) 	writel(pd->vidcon1, sfb->regs + VIDCON1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) 	[0] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) 		.has_osd_c	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) 		.osd_size_off	= 0x8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) 		.palette_sz	= 256,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) 		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) 				   VALID_BPP(18) | VALID_BPP(24)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) 	[1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) 		.has_osd_c	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) 		.has_osd_d	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) 		.osd_size_off	= 0xc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) 		.has_osd_alpha	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) 		.palette_sz	= 256,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) 		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) 				   VALID_BPP(18) | VALID_BPP(19) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) 				   VALID_BPP(24) | VALID_BPP(25) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) 				   VALID_BPP(28)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) 	[2] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) 		.has_osd_c	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) 		.has_osd_d	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) 		.osd_size_off	= 0xc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) 		.has_osd_alpha	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) 		.palette_sz	= 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) 		.palette_16bpp	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) 		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) 				   VALID_BPP(18) | VALID_BPP(19) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) 				   VALID_BPP(24) | VALID_BPP(25) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) 				   VALID_BPP(28)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) 	[3] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) 		.has_osd_c	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) 		.has_osd_alpha	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) 		.palette_sz	= 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) 		.palette_16bpp	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) 		.valid_bpp	= (VALID_BPP124  | VALID_BPP(16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) 				   VALID_BPP(18) | VALID_BPP(19) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) 				   VALID_BPP(24) | VALID_BPP(25) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) 				   VALID_BPP(28)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) 	[4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) 		.has_osd_c	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) 		.has_osd_alpha	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) 		.palette_sz	= 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) 		.palette_16bpp	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) 		.valid_bpp	= (VALID_BPP(1) | VALID_BPP(2) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) 				   VALID_BPP(16) | VALID_BPP(18) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) 				   VALID_BPP(19) | VALID_BPP(24) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) 				   VALID_BPP(25) | VALID_BPP(28)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) static struct s3c_fb_driverdata s3c_fb_data_64xx = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) 	.variant = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) 		.nr_windows	= 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) 		.vidtcon	= VIDTCON0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) 		.wincon		= WINCON(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) 		.winmap		= WINxMAP(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) 		.keycon		= WKEYCON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) 		.osd		= VIDOSD_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) 		.osd_stride	= 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) 		.buf_start	= VIDW_BUF_START(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) 		.buf_size	= VIDW_BUF_SIZE(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) 		.buf_end	= VIDW_BUF_END(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) 		.palette = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) 			[0] = 0x400,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) 			[1] = 0x800,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) 			[2] = 0x300,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) 			[3] = 0x320,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) 			[4] = 0x340,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) 		},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) 		.has_prtcon	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) 		.has_clksel	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) 	.win[0]	= &s3c_fb_data_64xx_wins[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) 	.win[1]	= &s3c_fb_data_64xx_wins[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) 	.win[2]	= &s3c_fb_data_64xx_wins[2],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) 	.win[3]	= &s3c_fb_data_64xx_wins[3],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) 	.win[4]	= &s3c_fb_data_64xx_wins[4],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) /* S3C2443/S3C2416 style hardware */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) 	.variant = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) 		.nr_windows	= 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) 		.is_2443	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) 		.vidtcon	= 0x08,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) 		.wincon		= 0x14,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) 		.winmap		= 0xd0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) 		.keycon		= 0xb0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) 		.osd		= 0x28,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) 		.osd_stride	= 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) 		.buf_start	= 0x64,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) 		.buf_size	= 0x94,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) 		.buf_end	= 0x7c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) 		.palette = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) 			[0] = 0x400,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) 			[1] = 0x800,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) 		},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) 		.has_clksel	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) 	.win[0] = &(struct s3c_fb_win_variant) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) 		.palette_sz	= 256,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) 		.valid_bpp	= VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) 	.win[1] = &(struct s3c_fb_win_variant) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) 		.has_osd_c	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) 		.has_osd_alpha	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) 		.palette_sz	= 256,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) 		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) 				   VALID_BPP(18) | VALID_BPP(19) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) 				   VALID_BPP(24) | VALID_BPP(25) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) 				   VALID_BPP(28)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) static const struct platform_device_id s3c_fb_driver_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) 		.name		= "s3c-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) 		.driver_data	= (unsigned long)&s3c_fb_data_64xx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) 		.name		= "s3c2443-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) 		.driver_data	= (unsigned long)&s3c_fb_data_s3c2443,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) 	{},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) static const struct dev_pm_ops s3cfb_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) 	SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) 	SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) 			   NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) static struct platform_driver s3c_fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) 	.probe		= s3c_fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) 	.remove		= s3c_fb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) 	.id_table	= s3c_fb_driver_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) 	.driver		= {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) 		.name	= "s3c-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) 		.pm	= &s3cfb_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) module_platform_driver(s3c_fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) MODULE_ALIAS("platform:s3c-fb");