// SPDX-License-Identifier: GPL-2.0-only/* linux/drivers/video/s3c-fb.c * * Copyright 2008 Openmoko Inc. * Copyright 2008-2010 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * 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) do { \ pr_debug("%s: %08x => %p\n", __func__, (unsigned int)v, r); \ __raw_writel(v, r); \} while (0)#endif /* FB_S3C_DEBUG_REGWRITE */ /* irq_flags bits */#define S3C_FB_VSYNC_IRQ_EN 0 #define VSYNC_TIMEOUT_MSEC 50 struct s3c_fb; #define VALID_BPP(x) (1 << ((x) - 1)) #define OSD_BASE(win, variant) ((variant).osd + ((win) * (variant).osd_stride))#define VIDOSD_A(win, variant) (OSD_BASE(win, variant) + 0x00)#define VIDOSD_B(win, variant) (OSD_BASE(win, variant) + 0x04)#define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08)#define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C) /** * 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 { unsigned int is_2443:1; unsigned short nr_windows; unsigned int vidtcon; unsigned short wincon; unsigned short winmap; unsigned short keycon; unsigned short buf_start; unsigned short buf_end; unsigned short buf_size; unsigned short osd; unsigned short osd_stride; unsigned short palette[S3C_FB_MAX_WIN]; unsigned int has_prtcon:1; unsigned int has_shadowcon:1; unsigned int has_blendcon:1; unsigned int has_clksel:1; unsigned int has_fixvclk:1;}; /** * 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 { unsigned int has_osd_c:1; unsigned int has_osd_d:1; unsigned int has_osd_alpha:1; unsigned int palette_16bpp:1; unsigned short osd_size_off; unsigned short palette_sz; u32 valid_bpp;}; /** * 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_variant variant; struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN];}; /** * struct s3c_fb_palette - palette information * @r: Red bitfield. * @g: Green bitfield. * @b: Blue bitfield. * @a: Alpha bitfield. */struct s3c_fb_palette { struct fb_bitfield r; struct fb_bitfield g; struct fb_bitfield b; struct fb_bitfield a;}; /** * 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_pd_win *windata; struct s3c_fb *parent; struct fb_info *fbinfo; struct s3c_fb_palette palette; struct s3c_fb_win_variant variant; u32 *palette_buffer; u32 pseudo_palette[16]; unsigned int index;}; /** * struct s3c_fb_vsync - vsync information * @wait: a queue for processes waiting for vsync * @count: vsync interrupt count */struct s3c_fb_vsync { wait_queue_head_t wait; unsigned int count;}; /** * 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 { spinlock_t slock; struct device *dev; struct clk *bus_clk; struct clk *lcd_clk; void __iomem *regs; struct s3c_fb_variant variant; unsigned char enabled; bool output_on; struct s3c_fb_platdata *pdata; struct s3c_fb_win *windows[S3C_FB_MAX_WIN]; int irq_no; unsigned long irq_flags; struct s3c_fb_vsync vsync_info;}; /** * 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){ return win->variant.valid_bpp & VALID_BPP(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){ struct s3c_fb_win *win = info->par; struct s3c_fb *sfb = win->parent; dev_dbg(sfb->dev, "checking parameters\n"); var->xres_virtual = max(var->xres_virtual, var->xres); var->yres_virtual = max(var->yres_virtual, var->yres); if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) { dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n", win->index, var->bits_per_pixel); return -EINVAL; } /* always ensure these are zero, for drop through cases below */ var->transp.offset = 0; var->transp.length = 0; switch (var->bits_per_pixel) { case 1: case 2: case 4: case 8: if (sfb->variant.palette[win->index] != 0) { /* non palletised, A:1,R:2,G:3,B:2 mode */ var->red.offset = 5; var->green.offset = 2; var->blue.offset = 0; var->red.length = 2; var->green.length = 3; var->blue.length = 2; var->transp.offset = 7; var->transp.length = 1; } else { var->red.offset = 0; var->red.length = var->bits_per_pixel; var->green = var->red; var->blue = var->red; } break; case 19: /* 666 with one bit alpha/transparency */ var->transp.offset = 18; var->transp.length = 1; fallthrough; case 18: var->bits_per_pixel = 32; /* 666 format */ var->red.offset = 12; var->green.offset = 6; var->blue.offset = 0; var->red.length = 6; var->green.length = 6; var->blue.length = 6; break; case 16: /* 16 bpp, 565 format */ var->red.offset = 11; var->green.offset = 5; var->blue.offset = 0; var->red.length = 5; var->green.length = 6; var->blue.length = 5; break; case 32: case 28: case 25: var->transp.length = var->bits_per_pixel - 24; var->transp.offset = 24; fallthrough; case 24: /* our 24bpp is unpacked, so 32bpp */ var->bits_per_pixel = 32; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; break; default: dev_err(sfb->dev, "invalid bpp\n"); return -EINVAL; } dev_dbg(sfb->dev, "%s: verified parameters\n", __func__); return 0;} /** * 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){ unsigned long clk; unsigned long long tmp; unsigned int result; if (sfb->variant.has_clksel) clk = clk_get_rate(sfb->bus_clk); else clk = clk_get_rate(sfb->lcd_clk); tmp = (unsigned long long)clk; tmp *= pixclk; do_div(tmp, 1000000000UL); result = (unsigned int)tmp / 1000; dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n", pixclk, clk, result, result ? clk / result : clk); return result;} /** * 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){ int pix_per_word; if (bpp > 16) return pix; pix_per_word = (8 * 32) / bpp; return ALIGN(pix, pix_per_word);} /** * 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){ struct s3c_fb *sfb = win->parent; /* OSD can be set up if osd_size_off != 0 for this window */ if (win->variant.osd_size_off) writel(size, sfb->regs + OSD_BASE(win->index, sfb->variant) + win->variant.osd_size_off);} /** * 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){ struct s3c_fb *sfb = win->parent; if (win->variant.has_osd_alpha) writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant));} /** * 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){ struct s3c_fb *sfb = win->parent; u32 reg; if (protect) { if (sfb->variant.has_prtcon) { writel(PRTCON_PROTECT, sfb->regs + PRTCON); } else if (sfb->variant.has_shadowcon) { reg = readl(sfb->regs + SHADOWCON); writel(reg | SHADOWCON_WINx_PROTECT(win->index), sfb->regs + SHADOWCON); } } else { if (sfb->variant.has_prtcon) { writel(0, sfb->regs + PRTCON); } else if (sfb->variant.has_shadowcon) { reg = readl(sfb->regs + SHADOWCON); writel(reg & ~SHADOWCON_WINx_PROTECT(win->index), sfb->regs + SHADOWCON); } }} /** * 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){ u32 vidcon0 = readl(sfb->regs + VIDCON0); if (enable && !sfb->output_on) pm_runtime_get_sync(sfb->dev); if (enable) { vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F; } else { /* see the note in the framebuffer datasheet about * why you cannot take both of these bits down at the * same time. */ if (vidcon0 & VIDCON0_ENVID) { vidcon0 |= VIDCON0_ENVID; vidcon0 &= ~VIDCON0_ENVID_F; } } writel(vidcon0, sfb->regs + VIDCON0); if (!enable && sfb->output_on) pm_runtime_put_sync(sfb->dev); sfb->output_on = 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){ struct fb_var_screeninfo *var = &info->var; struct s3c_fb_win *win = info->par; struct s3c_fb *sfb = win->parent; void __iomem *regs = sfb->regs; void __iomem *buf; int win_no = win->index; u32 alpha = 0; u32 data; u32 pagewidth; dev_dbg(sfb->dev, "setting framebuffer parameters\n"); pm_runtime_get_sync(sfb->dev);Lines 1–500 of 1802. Load more
// SPDX-License-Identifier: GPL-2.0-only /* linux/drivers/video/s3c-fb.c * * Copyright 2008 Openmoko Inc. * Copyright 2008-2010 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * 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) do { \ pr_debug("%s: %08x => %p\n", __func__, (unsigned int)v, r); \ __raw_writel(v, r); \ } while (0) #endif /* FB_S3C_DEBUG_REGWRITE */ /* irq_flags bits */ #define S3C_FB_VSYNC_IRQ_EN 0 #define VSYNC_TIMEOUT_MSEC 50 struct s3c_fb; #define VALID_BPP(x) (1 << ((x) - 1)) #define OSD_BASE(win, variant) ((variant).osd + ((win) * (variant).osd_stride)) #define VIDOSD_A(win, variant) (OSD_BASE(win, variant) + 0x00) #define VIDOSD_B(win, variant) (OSD_BASE(win, variant) + 0x04) #define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08) #define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C) /** * 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 { unsigned int is_2443:1; unsigned short nr_windows; unsigned int vidtcon; unsigned short wincon; unsigned short winmap; unsigned short keycon; unsigned short buf_start; unsigned short buf_end; unsigned short buf_size; unsigned short osd; unsigned short osd_stride; unsigned short palette[S3C_FB_MAX_WIN]; unsigned int has_prtcon:1; unsigned int has_shadowcon:1; unsigned int has_blendcon:1; unsigned int has_clksel:1; unsigned int has_fixvclk:1; }; /** * 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 { unsigned int has_osd_c:1; unsigned int has_osd_d:1; unsigned int has_osd_alpha:1; unsigned int palette_16bpp:1; unsigned short osd_size_off; unsigned short palette_sz; u32 valid_bpp; }; /** * 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_variant variant; struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN]; }; /** * struct s3c_fb_palette - palette information * @r: Red bitfield. * @g: Green bitfield. * @b: Blue bitfield. * @a: Alpha bitfield. */ struct s3c_fb_palette { struct fb_bitfield r; struct fb_bitfield g; struct fb_bitfield b; struct fb_bitfield a; }; /** * 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_pd_win *windata; struct s3c_fb *parent; struct fb_info *fbinfo; struct s3c_fb_palette palette; struct s3c_fb_win_variant variant; u32 *palette_buffer; u32 pseudo_palette[16]; unsigned int index; }; /** * struct s3c_fb_vsync - vsync information * @wait: a queue for processes waiting for vsync * @count: vsync interrupt count */ struct s3c_fb_vsync { wait_queue_head_t wait; unsigned int count; }; /** * 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 { spinlock_t slock; struct device *dev; struct clk *bus_clk; struct clk *lcd_clk; void __iomem *regs; struct s3c_fb_variant variant; unsigned char enabled; bool output_on; struct s3c_fb_platdata *pdata; struct s3c_fb_win *windows[S3C_FB_MAX_WIN]; int irq_no; unsigned long irq_flags; struct s3c_fb_vsync vsync_info; }; /** * 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) { return win->variant.valid_bpp & VALID_BPP(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) { struct s3c_fb_win *win = info->par; struct s3c_fb *sfb = win->parent; dev_dbg(sfb->dev, "checking parameters\n"); var->xres_virtual = max(var->xres_virtual, var->xres); var->yres_virtual = max(var->yres_virtual, var->yres); if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) { dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n", win->index, var->bits_per_pixel); return -EINVAL; } /* always ensure these are zero, for drop through cases below */ var->transp.offset = 0; var->transp.length = 0; switch (var->bits_per_pixel) { case 1: case 2: case 4: case 8: if (sfb->variant.palette[win->index] != 0) { /* non palletised, A:1,R:2,G:3,B:2 mode */ var->red.offset = 5; var->green.offset = 2; var->blue.offset = 0; var->red.length = 2; var->green.length = 3; var->blue.length = 2; var->transp.offset = 7; var->transp.length = 1; } else { var->red.offset = 0; var->red.length = var->bits_per_pixel; var->green = var->red; var->blue = var->red; } break; case 19: /* 666 with one bit alpha/transparency */ var->transp.offset = 18; var->transp.length = 1; fallthrough; case 18: var->bits_per_pixel = 32; /* 666 format */ var->red.offset = 12; var->green.offset = 6; var->blue.offset = 0; var->red.length = 6; var->green.length = 6; var->blue.length = 6; break; case 16: /* 16 bpp, 565 format */ var->red.offset = 11; var->green.offset = 5; var->blue.offset = 0; var->red.length = 5; var->green.length = 6; var->blue.length = 5; break; case 32: case 28: case 25: var->transp.length = var->bits_per_pixel - 24; var->transp.offset = 24; fallthrough; case 24: /* our 24bpp is unpacked, so 32bpp */ var->bits_per_pixel = 32; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; break; default: dev_err(sfb->dev, "invalid bpp\n"); return -EINVAL; } dev_dbg(sfb->dev, "%s: verified parameters\n", __func__); return 0; } /** * 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) { unsigned long clk; unsigned long long tmp; unsigned int result; if (sfb->variant.has_clksel) clk = clk_get_rate(sfb->bus_clk); else clk = clk_get_rate(sfb->lcd_clk); tmp = (unsigned long long)clk; tmp *= pixclk; do_div(tmp, 1000000000UL); result = (unsigned int)tmp / 1000; dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n", pixclk, clk, result, result ? clk / result : clk); return result; } /** * 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) { int pix_per_word; if (bpp > 16) return pix; pix_per_word = (8 * 32) / bpp; return ALIGN(pix, pix_per_word); } /** * 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) { struct s3c_fb *sfb = win->parent; /* OSD can be set up if osd_size_off != 0 for this window */ if (win->variant.osd_size_off) writel(size, sfb->regs + OSD_BASE(win->index, sfb->variant) + win->variant.osd_size_off); } /** * 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) { struct s3c_fb *sfb = win->parent; if (win->variant.has_osd_alpha) writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant)); } /** * 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) { struct s3c_fb *sfb = win->parent; u32 reg; if (protect) { if (sfb->variant.has_prtcon) { writel(PRTCON_PROTECT, sfb->regs + PRTCON); } else if (sfb->variant.has_shadowcon) { reg = readl(sfb->regs + SHADOWCON); writel(reg | SHADOWCON_WINx_PROTECT(win->index), sfb->regs + SHADOWCON); } } else { if (sfb->variant.has_prtcon) { writel(0, sfb->regs + PRTCON); } else if (sfb->variant.has_shadowcon) { reg = readl(sfb->regs + SHADOWCON); writel(reg & ~SHADOWCON_WINx_PROTECT(win->index), sfb->regs + SHADOWCON); } } } /** * 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) { u32 vidcon0 = readl(sfb->regs + VIDCON0); if (enable && !sfb->output_on) pm_runtime_get_sync(sfb->dev); if (enable) { vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F; } else { /* see the note in the framebuffer datasheet about * why you cannot take both of these bits down at the * same time. */ if (vidcon0 & VIDCON0_ENVID) { vidcon0 |= VIDCON0_ENVID; vidcon0 &= ~VIDCON0_ENVID_F; } } writel(vidcon0, sfb->regs + VIDCON0); if (!enable && sfb->output_on) pm_runtime_put_sync(sfb->dev); sfb->output_on = 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) { struct fb_var_screeninfo *var = &info->var; struct s3c_fb_win *win = info->par; struct s3c_fb *sfb = win->parent; void __iomem *regs = sfb->regs; void __iomem *buf; int win_no = win->index; u32 alpha = 0; u32 data; u32 pagewidth; dev_dbg(sfb->dev, "setting framebuffer parameters\n"); pm_runtime_get_sync(sfb->dev);