^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");