// SPDX-License-Identifier: GPL-2.0-only /* linux/drivers/video/s3c-fb.c * * Copyright 2008 Openmoko Inc. * Copyright 2008-2010 Simtec Electronics * Ben Dooks <[email protected]> * http://armlinux.simtec.co.uk/ * * Samsung SoC Framebuffer driver */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/clk.h> #include <linux/fb.h> #include <linux/io.h> #include <linux/uaccess.h> #include <linux/interrupt.h> #include <linux/pm_runtime.h> #include <linux/platform_data/video_s3c.h> #include <video/samsung_fimd.h> /* This driver will export a number of framebuffer interfaces depending * on the configuration passed in via the platform data. Each fb instance * maps to a hardware window. Currently there is no support for runtime * setting of the alpha-blending functions that each window has, so only * window 0 is actually useful. * * Window 0 is treated specially, it is used for the basis of the LCD * output timings and as the control for the output power-down state. */ /* note, the previous use of <mach/regs-fb.h> to get platform specific data * has been replaced by using the platform device name to pick the correct * configuration data for the system. */ #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE #undef writel #define writel(v, r) … #endif /* FB_S3C_DEBUG_REGWRITE */ /* irq_flags bits */ #define S3C_FB_VSYNC_IRQ_EN … #define VSYNC_TIMEOUT_MSEC … struct s3c_fb; #define VALID_BPP(x) … #define OSD_BASE(win, variant) … #define VIDOSD_A(win, variant) … #define VIDOSD_B(win, variant) … #define VIDOSD_C(win, variant) … #define VIDOSD_D(win, variant) … /** * struct s3c_fb_variant - fb variant information * @is_2443: Set if S3C2443/S3C2416 style hardware. * @nr_windows: The number of windows. * @vidtcon: The base for the VIDTCONx registers * @wincon: The base for the WINxCON registers. * @winmap: The base for the WINxMAP registers. * @keycon: The abse for the WxKEYCON registers. * @buf_start: Offset of buffer start registers. * @buf_size: Offset of buffer size registers. * @buf_end: Offset of buffer end registers. * @osd: The base for the OSD registers. * @osd_stride: stride of osd * @palette: Address of palette memory, or 0 if none. * @has_prtcon: Set if has PRTCON register. * @has_shadowcon: Set if has SHADOWCON register. * @has_blendcon: Set if has BLENDCON register. * @has_clksel: Set if VIDCON0 register has CLKSEL bit. * @has_fixvclk: Set if VIDCON1 register has FIXVCLK bits. */ struct s3c_fb_variant { … }; /** * struct s3c_fb_win_variant * @has_osd_c: Set if has OSD C register. * @has_osd_d: Set if has OSD D register. * @has_osd_alpha: Set if can change alpha transparency for a window. * @palette_sz: Size of palette in entries. * @palette_16bpp: Set if palette is 16bits wide. * @osd_size_off: If != 0, supports setting up OSD for a window; the appropriate * register is located at the given offset from OSD_BASE. * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel. * * valid_bpp bit x is set if (x+1)BPP is supported. */ struct s3c_fb_win_variant { … }; /** * struct s3c_fb_driverdata - per-device type driver data for init time. * @variant: The variant information for this driver. * @win: The window information for each window. */ struct s3c_fb_driverdata { … }; /** * struct s3c_fb_palette - palette information * @r: Red bitfield. * @g: Green bitfield. * @b: Blue bitfield. * @a: Alpha bitfield. */ struct s3c_fb_palette { … }; /** * struct s3c_fb_win - per window private data for each framebuffer. * @windata: The platform data supplied for the window configuration. * @parent: The hardware that this window is part of. * @fbinfo: Pointer pack to the framebuffer info for this window. * @variant: The variant information for this window. * @palette_buffer: Buffer/cache to hold palette entries. * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/ * @index: The window number of this window. * @palette: The bitfields for changing r/g/b into a hardware palette entry. */ struct s3c_fb_win { … }; /** * struct s3c_fb_vsync - vsync information * @wait: a queue for processes waiting for vsync * @count: vsync interrupt count */ struct s3c_fb_vsync { … }; /** * struct s3c_fb - overall hardware state of the hardware * @slock: The spinlock protection for this data structure. * @dev: The device that we bound to, for printing, etc. * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. * @lcd_clk: The clk (sclk) feeding pixclk. * @regs: The mapped hardware registers. * @variant: Variant information for this hardware. * @enabled: A bitmask of enabled hardware windows. * @output_on: Flag if the physical output is enabled. * @pdata: The platform configuration data passed with the device. * @windows: The hardware windows that have been claimed. * @irq_no: IRQ line number * @irq_flags: irq flags * @vsync_info: VSYNC-related information (count, queues...) */ struct s3c_fb { … }; /** * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode. * @win: The device window. * @bpp: The bit depth. */ static bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp) { … } /** * s3c_fb_check_var() - framebuffer layer request to verify a given mode. * @var: The screen information to verify. * @info: The framebuffer device. * * Framebuffer layer call to verify the given information and allow us to * update various information depending on the hardware capabilities. */ static int s3c_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { … } /** * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock. * @sfb: The hardware state. * @pixclk: The pixel clock wanted, in picoseconds. * * Given the specified pixel clock, work out the necessary divider to get * close to the output frequency. */ static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk) { … } /** * s3c_fb_align_word() - align pixel count to word boundary * @bpp: The number of bits per pixel * @pix: The value to be aligned. * * Align the given pixel count so that it will start on an 32bit word * boundary. */ static int s3c_fb_align_word(unsigned int bpp, unsigned int pix) { … } /** * vidosd_set_size() - set OSD size for a window * * @win: the window to set OSD size for * @size: OSD size register value */ static void vidosd_set_size(struct s3c_fb_win *win, u32 size) { … } /** * vidosd_set_alpha() - set alpha transparency for a window * * @win: the window to set OSD size for * @alpha: alpha register value */ static void vidosd_set_alpha(struct s3c_fb_win *win, u32 alpha) { … } /** * shadow_protect_win() - disable updating values from shadow registers at vsync * * @win: window to protect registers for * @protect: 1 to protect (disable updates) */ static void shadow_protect_win(struct s3c_fb_win *win, bool protect) { … } /** * s3c_fb_enable() - Set the state of the main LCD output * @sfb: The main framebuffer state. * @enable: The state to set. */ static void s3c_fb_enable(struct s3c_fb *sfb, int enable) { … } /** * s3c_fb_set_par() - framebuffer request to set new framebuffer state. * @info: The framebuffer to change. * * Framebuffer layer request to set a new mode for the specified framebuffer */ static int s3c_fb_set_par(struct fb_info *info) { … } /** * s3c_fb_update_palette() - set or schedule a palette update. * @sfb: The hardware information. * @win: The window being updated. * @reg: The palette index being changed. * @value: The computed palette value. * * Change the value of a palette register, either by directly writing to * the palette (this requires the palette RAM to be disconnected from the * hardware whilst this is in progress) or schedule the update for later. * * At the moment, since we have no VSYNC interrupt support, we simply set * the palette entry directly. */ static void s3c_fb_update_palette(struct s3c_fb *sfb, struct s3c_fb_win *win, unsigned int reg, u32 value) { … } static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) { … } /** * s3c_fb_setcolreg() - framebuffer layer request to change palette. * @regno: The palette index to change. * @red: The red field for the palette data. * @green: The green field for the palette data. * @blue: The blue field for the palette data. * @transp: The transparency (alpha) field for the palette data. * @info: The framebuffer being changed. */ static int s3c_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { … } /** * s3c_fb_blank() - blank or unblank the given window * @blank_mode: The blank state from FB_BLANK_* * @info: The framebuffer to blank. * * Framebuffer layer request to change the power state. */ static int s3c_fb_blank(int blank_mode, struct fb_info *info) { … } /** * s3c_fb_pan_display() - Pan the display. * * Note that the offsets can be written to the device at any time, as their * values are latched at each vsync automatically. This also means that only * the last call to this function will have any effect on next vsync, but * there is no need to sleep waiting for it to prevent tearing. * * @var: The screen information to verify. * @info: The framebuffer device. */ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { … } /** * s3c_fb_enable_irq() - enable framebuffer interrupts * @sfb: main hardware state */ static void s3c_fb_enable_irq(struct s3c_fb *sfb) { … } /** * s3c_fb_disable_irq() - disable framebuffer interrupts * @sfb: main hardware state */ static void s3c_fb_disable_irq(struct s3c_fb *sfb) { … } static irqreturn_t s3c_fb_irq(int irq, void *dev_id) { … } /** * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout * @sfb: main hardware state * @crtc: head index. */ static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc) { … } static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { … } static const struct fb_ops s3c_fb_ops = …; /** * s3c_fb_missing_pixclock() - calculates pixel clock * @mode: The video mode to change. * * Calculate the pixel clock when none has been given through platform data. */ static void s3c_fb_missing_pixclock(struct fb_videomode *mode) { … } /** * s3c_fb_alloc_memory() - allocate display memory for framebuffer window * @sfb: The base resources for the hardware. * @win: The window to initialise memory for. * * Allocate memory for the given framebuffer. */ static int s3c_fb_alloc_memory(struct s3c_fb *sfb, struct s3c_fb_win *win) { … } /** * s3c_fb_free_memory() - free the display memory for the given window * @sfb: The base resources for the hardware. * @win: The window to free the display memory for. * * Free the display memory allocated by s3c_fb_alloc_memory(). */ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win) { … } /** * s3c_fb_release_win() - release resources for a framebuffer window. * @sfb: The base resources for the hardware. * @win: The window to cleanup the resources for. * * Release the resources that where claimed for the hardware window, * such as the framebuffer instance and any memory claimed for it. */ static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win) { … } /** * s3c_fb_probe_win() - register an hardware window * @sfb: The base resources for the hardware * @win_no: The window number * @variant: The variant information for this window. * @res: Pointer to where to place the resultant window. * * Allocate and do the basic initialisation for one of the hardware's graphics * windows. */ static int s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, struct s3c_fb_win_variant *variant, struct s3c_fb_win **res) { … } /** * s3c_fb_set_rgb_timing() - set video timing for rgb interface. * @sfb: The base resources for the hardware. * * Set horizontal and vertical lcd rgb interface timing. */ static void s3c_fb_set_rgb_timing(struct s3c_fb *sfb) { … } /** * s3c_fb_clear_win() - clear hardware window registers. * @sfb: The base resources for the hardware. * @win: The window to process. * * Reset the specific window registers to a known state. */ static void s3c_fb_clear_win(struct s3c_fb *sfb, int win) { … } static int s3c_fb_probe(struct platform_device *pdev) { … } /** * s3c_fb_remove() - Cleanup on module finalisation * @pdev: The platform device we are bound to. * * Shutdown and then release all the resources that the driver allocated * on initialisation. */ static void s3c_fb_remove(struct platform_device *pdev) { … } #ifdef CONFIG_PM_SLEEP static int s3c_fb_suspend(struct device *dev) { … } static int s3c_fb_resume(struct device *dev) { … } #endif #ifdef CONFIG_PM static int s3c_fb_runtime_suspend(struct device *dev) { … } static int s3c_fb_runtime_resume(struct device *dev) { … } #endif #define VALID_BPP124 … #define VALID_BPP1248 … static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = …; static struct s3c_fb_driverdata s3c_fb_data_64xx = …; /* S3C2443/S3C2416 style hardware */ static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = …; static const struct platform_device_id s3c_fb_driver_ids[] = …; MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids); static const struct dev_pm_ops s3cfb_pm_ops = …; static struct platform_driver s3c_fb_driver = …; module_platform_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;