^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/sm501fb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2006 Simtec Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Vincent Sanders <vince@simtec.co.uk>
^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) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Framebuffer driver for the Silicon Motion SM501
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^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/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/delay.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/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/div64.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/sm501.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/sm501-regs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include "edid.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static char *fb_mode = "640x480-16@60";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static unsigned long default_bpp = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static const struct fb_videomode sm501_default_mode = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) .refresh = 60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .xres = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .yres = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .pixclock = 20833,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) .left_margin = 142,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) .right_margin = 13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) .upper_margin = 21,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .lower_margin = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) .hsync_len = 69,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) .vsync_len = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .vmode = FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define NR_PALETTE 256
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) enum sm501_controller {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) HEAD_CRT = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) HEAD_PANEL = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* SM501 memory address.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * This structure is used to track memory usage within the SM501 framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * allocation. The sm_addr field is stored as an offset as it is often used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * against both the physical and mapped addresses.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct sm501_mem {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) unsigned long size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned long sm_addr; /* offset from base of sm501 fb. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) void __iomem *k_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* private data that is shared between all frambuffers* */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct sm501fb_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct fb_info *fb[2]; /* fb info for both heads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct resource *fbmem_res; /* framebuffer resource */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct resource *regs_res; /* registers resource */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct resource *regs2d_res; /* 2d registers resource */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct sm501_platdata_fb *pdata; /* our platform data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned long pm_crt_ctrl; /* pm: crt ctrl save */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int swap_endian; /* set to swap rgb=>bgr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) void __iomem *regs; /* remapped registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) void __iomem *regs2d; /* 2d remapped registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) void __iomem *fbmem; /* remapped framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) size_t fbmem_len; /* length of remapped region */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) u8 *edid_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* per-framebuffer private data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct sm501fb_par {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) u32 pseudo_palette[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) enum sm501_controller head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct sm501_mem cursor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct sm501_mem screen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct fb_ops ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) void *store_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) void *store_cursor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) void __iomem *cursor_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct sm501fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /* Helper functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static inline int h_total(struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return var->xres + var->left_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) var->right_margin + var->hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static inline int v_total(struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return var->yres + var->upper_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) var->lower_margin + var->vsync_len;
^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) /* sm501fb_sync_regs()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * This call is mainly for PCI bus systems where we need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * ensure that any writes to the bus are completed before the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * next phase, or after completing a function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) static inline void sm501fb_sync_regs(struct sm501fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) smc501_readl(info->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* sm501_alloc_mem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * This is an attempt to lay out memory for the two framebuffers and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * everything else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * |fbmem_res->start fbmem_res->end|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * The "spare" space is for the 2d engine data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * the fixed is space for the cursors (2x1Kbyte)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * we need to allocate memory for the 2D acceleration engine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * command list and the data for the engine to deal with.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * - all allocations must be 128bit aligned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * - cursors are 64x64x2 bits (1Kbyte)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) #define SM501_MEMF_CURSOR (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #define SM501_MEMF_PANEL (2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #define SM501_MEMF_CRT (4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #define SM501_MEMF_ACCEL (8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) unsigned int why, size_t size, u32 smem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct sm501fb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct fb_info *fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) unsigned int ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) unsigned int end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) switch (why) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) case SM501_MEMF_CURSOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) ptr = inf->fbmem_len - size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) inf->fbmem_len = ptr; /* adjust available memory. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) case SM501_MEMF_PANEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (size > inf->fbmem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) ptr = inf->fbmem_len - size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) fbi = inf->fb[HEAD_CRT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* round down, some programs such as directfb do not draw
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * 0,0 correctly unless the start is aligned to a page start.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (ptr > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) ptr &= ~(PAGE_SIZE - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (fbi && ptr < smem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) case SM501_MEMF_CRT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) ptr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /* check to see if we have panel memory allocated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * which would put an limit on available memory. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) fbi = inf->fb[HEAD_PANEL];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (fbi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) par = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) end = par->screen.k_addr ? par->screen.sm_addr : inf->fbmem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) end = inf->fbmem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if ((ptr + size) > end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) case SM501_MEMF_ACCEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) fbi = inf->fb[HEAD_CRT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) ptr = fbi ? smem_len : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) fbi = inf->fb[HEAD_PANEL];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (fbi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) par = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) end = par->screen.sm_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) end = inf->fbmem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if ((ptr + size) > end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) mem->size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) mem->sm_addr = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) mem->k_addr = inf->fbmem + ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) dev_dbg(inf->dev, "%s: result %08lx, %p - %u, %zd\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) __func__, mem->sm_addr, mem->k_addr, why, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) /* sm501fb_ps_to_hz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) * Converts a period in picoseconds to Hz.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * Note, we try to keep this in Hz to minimise rounding with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * the limited PLL settings on the SM501.
^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) static unsigned long sm501fb_ps_to_hz(unsigned long psvalue)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) unsigned long long numerator=1000000000000ULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) /* 10^12 / picosecond period gives frequency in Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) do_div(numerator, psvalue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return (unsigned long)numerator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) /* sm501fb_hz_to_ps is identical to the opposite transform */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) #define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) /* sm501fb_setup_gamma
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * Programs a linear 1.0 gamma ramp in case the gamma
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * correction is enabled without programming anything else.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static void sm501fb_setup_gamma(struct sm501fb_info *fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) unsigned long palette)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) unsigned long value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* set gamma values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) for (offset = 0; offset < 256 * 4; offset += 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) smc501_writel(value, fbi->regs + palette + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) value += 0x010101; /* Advance RGB by 1,1,1.*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) /* sm501fb_check_var
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * check common variables for both panel and crt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static int sm501fb_check_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) struct sm501fb_info *sm = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) /* check we can fit these values into the registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (var->hsync_len > 255 || var->vsync_len > 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) /* hdisplay end and hsync start */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if ((var->xres + var->right_margin) > 4096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /* vdisplay end and vsync start */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if ((var->yres + var->lower_margin) > 2048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) /* hard limits of device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (h_total(var) > 4096 || v_total(var) > 2048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) /* check our line length is going to be 128 bit aligned */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) tmp = (var->xres * var->bits_per_pixel) / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if ((tmp & 15) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* check the virtual size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) if (var->xres_virtual > 4096 || var->yres_virtual > 2048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) /* can cope with 8,16 or 32bpp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (var->bits_per_pixel <= 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) var->bits_per_pixel = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) else if (var->bits_per_pixel <= 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) var->bits_per_pixel = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) else if (var->bits_per_pixel == 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) var->bits_per_pixel = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) /* set r/g/b positions and validate bpp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) switch(var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) var->red.length = var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) var->red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) var->green.length = var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) var->green.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) var->blue.length = var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) var->blue.offset = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) var->green.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) var->red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) var->red.offset = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) var->green.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) var->green.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) var->red.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) var->green.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) var->blue.offset = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) var->transp.offset = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) var->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * sm501fb_check_var_crt():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) * check the parameters for the CRT head, and either bring them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) * back into range, or return -EINVAL.
^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) static int sm501fb_check_var_crt(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return sm501fb_check_var(var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) /* sm501fb_check_var_pnl():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) * check the parameters for the CRT head, and either bring them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) * back into range, or return -EINVAL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) static int sm501fb_check_var_pnl(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return sm501fb_check_var(var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) /* sm501fb_set_par_common
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) * set common registers for framebuffers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) static int sm501fb_set_par_common(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) unsigned long pixclock; /* pixelclock in Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) unsigned long sm501pixclock; /* pixelclock the 501 can achieve in Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) unsigned int mem_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) unsigned int clock_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) unsigned int head_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) unsigned int smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) __func__, var->xres, var->yres, var->bits_per_pixel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) var->xres_virtual, var->yres_virtual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) switch (par->head) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) case HEAD_CRT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) mem_type = SM501_MEMF_CRT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) clock_type = SM501_CLOCK_V2XCLK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) head_addr = SM501_DC_CRT_FB_ADDR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) case HEAD_PANEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) mem_type = SM501_MEMF_PANEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) clock_type = SM501_CLOCK_P2XCLK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) head_addr = SM501_DC_PANEL_FB_ADDR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) mem_type = 0; /* stop compiler warnings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) head_addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) clock_type = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) /* allocate fb memory within 501 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) smem_len = info->fix.line_length * var->yres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) info->fix.line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) dev_err(fbi->dev, "no memory available\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) mutex_lock(&info->mm_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) info->fix.smem_len = smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) mutex_unlock(&info->mm_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) info->screen_base = fbi->fbmem + par->screen.sm_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) info->screen_size = info->fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) /* set start of framebuffer to the screen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) smc501_writel(par->screen.sm_addr | SM501_ADDR_FLIP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) fbi->regs + head_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) /* program CRT clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) pixclock = sm501fb_ps_to_hz(var->pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) sm501pixclock = sm501_set_clock(fbi->dev->parent, clock_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) /* update fb layer with actual clock used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) var->pixclock = sm501fb_hz_to_ps(sm501pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) dev_dbg(fbi->dev, "%s: pixclock(ps) = %u, pixclock(Hz) = %lu, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) "sm501pixclock = %lu, error = %ld%%\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) __func__, var->pixclock, pixclock, sm501pixclock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) ((pixclock - sm501pixclock)*100)/pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /* sm501fb_set_par_geometry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) * set the geometry registers for specified framebuffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) static void sm501fb_set_par_geometry(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) void __iomem *base = fbi->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) unsigned long reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) if (par->head == HEAD_CRT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) base += SM501_DC_CRT_H_TOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) base += SM501_DC_PANEL_H_TOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) /* set framebuffer width and display width */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) reg = info->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) reg |= ((var->xres * var->bits_per_pixel)/8) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) smc501_writel(reg, fbi->regs + (par->head == HEAD_CRT ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) SM501_DC_CRT_FB_OFFSET : SM501_DC_PANEL_FB_OFFSET));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) /* program horizontal total */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) reg = (h_total(var) - 1) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) reg |= (var->xres - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) smc501_writel(reg, base + SM501_OFF_DC_H_TOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) /* program horizontal sync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) reg = var->hsync_len << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) reg |= var->xres + var->right_margin - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) smc501_writel(reg, base + SM501_OFF_DC_H_SYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) /* program vertical total */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) reg = (v_total(var) - 1) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) reg |= (var->yres - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) smc501_writel(reg, base + SM501_OFF_DC_V_TOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) /* program vertical sync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) reg = var->vsync_len << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) reg |= var->yres + var->lower_margin - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) smc501_writel(reg, base + SM501_OFF_DC_V_SYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) /* sm501fb_pan_crt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) * pan the CRT display output within an virtual framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) unsigned int bytes_pixel = info->var.bits_per_pixel / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) unsigned long reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) unsigned long xoffs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) xoffs = var->xoffset * bytes_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) reg = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) reg |= ((xoffs & 15) / bytes_pixel) << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) smc501_writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) reg = (par->screen.sm_addr + xoffs +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) var->yoffset * info->fix.line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) smc501_writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) /* sm501fb_pan_pnl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) * pan the panel display output within an virtual framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) unsigned long reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) reg = var->xoffset | (info->var.xres_virtual << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) reg = var->yoffset | (info->var.yres_virtual << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) /* sm501fb_set_par_crt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * Set the CRT video mode from the fb_info structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) static int sm501fb_set_par_crt(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) unsigned long control; /* control register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* activate new configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) /* enable CRT DAC - note 0 is on!*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) control = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) SM501_DC_CRT_CONTROL_GAMMA |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) SM501_DC_CRT_CONTROL_BLANK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) SM501_DC_CRT_CONTROL_SEL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) SM501_DC_CRT_CONTROL_CP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) SM501_DC_CRT_CONTROL_TVP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) /* set the sync polarities before we check data source */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) control |= SM501_DC_CRT_CONTROL_HSP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) control |= SM501_DC_CRT_CONTROL_VSP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) /* the head is displaying panel data... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) goto out_update;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) ret = sm501fb_set_par_common(info, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) dev_err(fbi->dev, "failed to set common parameters\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) return ret;
^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) sm501fb_pan_crt(var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) sm501fb_set_par_geometry(info, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) control |= SM501_FIFO_3; /* fill if >3 free slots */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) switch(var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) control |= SM501_DC_CRT_CONTROL_8BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) control |= SM501_DC_CRT_CONTROL_16BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) control |= SM501_DC_CRT_CONTROL_32BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) control |= SM501_DC_CRT_CONTROL_SEL; /* CRT displays CRT data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) control |= SM501_DC_CRT_CONTROL_TE; /* enable CRT timing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) control |= SM501_DC_CRT_CONTROL_ENABLE; /* enable CRT plane */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) out_update:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) dev_dbg(fbi->dev, "new control is %08lx\n", control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) smc501_writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) unsigned long control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) control = smc501_readl(ctrl_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) /* enable panel power */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) control |= SM501_DC_PANEL_CONTROL_VDD; /* FPVDDEN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) smc501_writel(control, ctrl_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) mdelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) control |= SM501_DC_PANEL_CONTROL_DATA; /* DATA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) smc501_writel(control, ctrl_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) mdelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) /* VBIASEN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) control &= ~SM501_DC_PANEL_CONTROL_BIAS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) control |= SM501_DC_PANEL_CONTROL_BIAS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) smc501_writel(control, ctrl_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) mdelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) control &= ~SM501_DC_PANEL_CONTROL_FPEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) control |= SM501_DC_PANEL_CONTROL_FPEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) smc501_writel(control, ctrl_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) mdelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) /* disable panel power */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) control |= SM501_DC_PANEL_CONTROL_FPEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) control &= ~SM501_DC_PANEL_CONTROL_FPEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) smc501_writel(control, ctrl_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) mdelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) control |= SM501_DC_PANEL_CONTROL_BIAS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) control &= ~SM501_DC_PANEL_CONTROL_BIAS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) smc501_writel(control, ctrl_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) mdelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) control &= ~SM501_DC_PANEL_CONTROL_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) smc501_writel(control, ctrl_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) mdelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) control &= ~SM501_DC_PANEL_CONTROL_VDD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) smc501_writel(control, ctrl_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) mdelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) /* sm501fb_set_par_pnl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) * Set the panel video mode from the fb_info structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) static int sm501fb_set_par_pnl(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) unsigned long control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) unsigned long reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) /* activate this new configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) ret = sm501fb_set_par_common(info, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) sm501fb_pan_pnl(var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) sm501fb_set_par_geometry(info, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) /* update control register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) control = smc501_readl(fbi->regs + SM501_DC_PANEL_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) control &= (SM501_DC_PANEL_CONTROL_GAMMA |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) SM501_DC_PANEL_CONTROL_VDD |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) SM501_DC_PANEL_CONTROL_DATA |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) SM501_DC_PANEL_CONTROL_BIAS |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) SM501_DC_PANEL_CONTROL_FPEN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) SM501_DC_PANEL_CONTROL_CP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) SM501_DC_PANEL_CONTROL_CK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) SM501_DC_PANEL_CONTROL_HP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) SM501_DC_PANEL_CONTROL_VP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) SM501_DC_PANEL_CONTROL_HPD |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) SM501_DC_PANEL_CONTROL_VPD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) control |= SM501_FIFO_3; /* fill if >3 free slots */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) switch(var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) control |= SM501_DC_PANEL_CONTROL_8BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) control |= SM501_DC_PANEL_CONTROL_16BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) control |= SM501_DC_PANEL_CONTROL_32BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) smc501_writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) /* panel plane top left and bottom right location */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) smc501_writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) reg = var->xres - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) reg |= (var->yres - 1) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) smc501_writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) /* program panel control register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) control |= SM501_DC_PANEL_CONTROL_TE; /* enable PANEL timing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) control |= SM501_DC_PANEL_CONTROL_EN; /* enable PANEL gfx plane */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) control |= SM501_DC_PANEL_CONTROL_HSP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) control |= SM501_DC_PANEL_CONTROL_VSP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) smc501_writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) /* ensure the panel interface is not tristated at this point */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) sm501_modify_reg(fbi->dev->parent, SM501_SYSTEM_CONTROL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) 0, SM501_SYSCTRL_PANEL_TRISTATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) /* power the panel up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) sm501fb_panel_power(fbi, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) /* chan_to_field
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) * convert a colour value into a field position
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) * from pxafb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) static inline unsigned int chan_to_field(unsigned int chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) struct fb_bitfield *bf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) chan &= 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) chan >>= 16 - bf->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) return chan << bf->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) /* sm501fb_setcolreg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) * set the colour mapping for modes that support palettised data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) static int sm501fb_setcolreg(unsigned regno,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) unsigned red, unsigned green, unsigned blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) unsigned transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) void __iomem *base = fbi->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) if (par->head == HEAD_CRT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) base += SM501_DC_CRT_PALETTE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) base += SM501_DC_PANEL_PALETTE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) switch (info->fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) /* true-colour, use pseuo-palette */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) if (regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) u32 *pal = par->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) val = chan_to_field(red, &info->var.red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) val |= chan_to_field(green, &info->var.green);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) val |= chan_to_field(blue, &info->var.blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) pal[regno] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) if (regno < 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) val = (red >> 8) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) val |= (green >> 8) << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) val |= blue >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) smc501_writel(val, base + (regno * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) return 1; /* unknown type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) /* sm501fb_blank_pnl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) * Blank or un-blank the panel interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) static int sm501fb_blank_pnl(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) switch (blank_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) sm501fb_panel_power(fbi, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) case FB_BLANK_UNBLANK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) sm501fb_panel_power(fbi, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) return 1;
^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) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) /* sm501fb_blank_crt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) * Blank or un-blank the crt interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) unsigned long ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) ctrl = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) switch (blank_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) ctrl |= SM501_DC_CRT_CONTROL_BLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) case FB_BLANK_UNBLANK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) ctrl &= ~SM501_DC_CRT_CONTROL_BLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) smc501_writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) sm501fb_sync_regs(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) /* sm501fb_cursor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) * set or change the hardware cursor parameters
^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 int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) void __iomem *base = fbi->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) unsigned long hwc_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) unsigned long fg, bg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) dev_dbg(fbi->dev, "%s(%p,%p)\n", __func__, info, cursor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) if (par->head == HEAD_CRT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) base += SM501_DC_CRT_HWC_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) base += SM501_DC_PANEL_HWC_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) /* check not being asked to exceed capabilities */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) if (cursor->image.width > 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) if (cursor->image.height > 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) if (cursor->image.depth > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) hwc_addr = smc501_readl(base + SM501_OFF_HWC_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) if (cursor->enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) smc501_writel(hwc_addr | SM501_HWC_EN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) base + SM501_OFF_HWC_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) smc501_writel(hwc_addr & ~SM501_HWC_EN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) base + SM501_OFF_HWC_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) /* set data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) if (cursor->set & FB_CUR_SETPOS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) unsigned int x = cursor->image.dx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) unsigned int y = cursor->image.dy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) if (x >= 2048 || y >= 2048 )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) dev_dbg(fbi->dev, "set position %d,%d\n", x, y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) //y += cursor->image.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) smc501_writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) if (cursor->set & FB_CUR_SETCMAP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) unsigned int bg_col = cursor->image.bg_color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) unsigned int fg_col = cursor->image.fg_color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) dev_dbg(fbi->dev, "%s: update cmap (%08x,%08x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) __func__, bg_col, fg_col);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) bg = ((info->cmap.red[bg_col] & 0xF8) << 8) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) ((info->cmap.green[bg_col] & 0xFC) << 3) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) ((info->cmap.blue[bg_col] & 0xF8) >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) fg = ((info->cmap.red[fg_col] & 0xF8) << 8) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) ((info->cmap.green[fg_col] & 0xFC) << 3) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) ((info->cmap.blue[fg_col] & 0xF8) >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) smc501_writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) smc501_writel(fg, base + SM501_OFF_HWC_COLOR_3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) if (cursor->set & FB_CUR_SETSIZE ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) /* SM501 cursor is a two bpp 64x64 bitmap this routine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) * clears it to transparent then combines the cursor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) * shape plane with the colour plane to set the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) * cursor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) int x, y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) const unsigned char *pcol = cursor->image.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) const unsigned char *pmsk = cursor->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) void __iomem *dst = par->cursor.k_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) unsigned char dcol = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) unsigned char dmsk = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) unsigned int op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) dev_dbg(fbi->dev, "%s: setting shape (%d,%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) __func__, cursor->image.width, cursor->image.height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) for (op = 0; op < (64*64*2)/8; op+=4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) smc501_writel(0x0, dst + op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) for (y = 0; y < cursor->image.height; y++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) for (x = 0; x < cursor->image.width; x++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) if ((x % 8) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) dcol = *pcol++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) dmsk = *pmsk++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) dcol >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) dmsk >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) if (dmsk & 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) op = (dcol & 1) ? 1 : 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) op <<= ((x % 4) * 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) op |= readb(dst + (x / 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) writeb(op, dst + (x / 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) dst += (64*2)/8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) sm501fb_sync_regs(fbi); /* ensure cursor data flushed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) /* sm501fb_crtsrc_show
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) * device attribute code to show where the crt output is sourced from
^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) static ssize_t sm501fb_crtsrc_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) struct sm501fb_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) unsigned long ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) ctrl &= SM501_DC_CRT_CONTROL_SEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) /* sm501fb_crtsrc_show
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) * device attribute code to set where the crt output is sourced from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) static ssize_t sm501fb_crtsrc_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) struct sm501fb_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) enum sm501_controller head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) unsigned long ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) if (len < 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) if (strncasecmp(buf, "crt", 3) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) head = HEAD_CRT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) else if (strncasecmp(buf, "panel", 5) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) head = HEAD_PANEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) dev_info(dev, "setting crt source to head %d\n", head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) if (head == HEAD_CRT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) ctrl |= SM501_DC_CRT_CONTROL_SEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) ctrl |= SM501_DC_CRT_CONTROL_TE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) ctrl &= ~SM501_DC_CRT_CONTROL_TE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) sm501fb_sync_regs(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) return len;
^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) /* Prepare the device_attr for registration with sysfs later */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) static DEVICE_ATTR(crt_src, 0664, sm501fb_crtsrc_show, sm501fb_crtsrc_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) /* sm501fb_show_regs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) * show the primary sm501 registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) unsigned int start, unsigned int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) void __iomem *mem = info->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) char *buf = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) unsigned int reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) for (reg = start; reg < (len + start); reg += 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) ptr += sprintf(ptr, "%08x = %08x\n", reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) smc501_readl(mem + reg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) return ptr - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) /* sm501fb_debug_show_crt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) * show the crt control and cursor registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) static ssize_t sm501fb_debug_show_crt(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) struct sm501fb_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) char *ptr = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_CONTROL, 0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_HWC_BASE, 0x10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) return ptr - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) static DEVICE_ATTR(fbregs_crt, 0444, sm501fb_debug_show_crt, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) /* sm501fb_debug_show_pnl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) * show the panel control and cursor registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) static ssize_t sm501fb_debug_show_pnl(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) struct sm501fb_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) char *ptr = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) ptr += sm501fb_show_regs(info, ptr, 0x0, 0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) ptr += sm501fb_show_regs(info, ptr, SM501_DC_PANEL_HWC_BASE, 0x10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) return ptr - buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) static struct attribute *sm501fb_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) &dev_attr_crt_src.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) &dev_attr_fbregs_pnl.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) &dev_attr_fbregs_crt.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) ATTRIBUTE_GROUPS(sm501fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) /* acceleration operations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) static int sm501fb_sync(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) int count = 1000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) /* wait for the 2d engine to be ready */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) while ((count > 0) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) (smc501_readl(fbi->regs + SM501_SYSTEM_CONTROL) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) SM501_SYSCTRL_2D_ENGINE_STATUS) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) if (count <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) dev_err(info->dev, "Timeout waiting for 2d engine sync\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) int width = area->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) int height = area->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) int sx = area->sx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) int sy = area->sy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) int dx = area->dx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) int dy = area->dy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) unsigned long rtl = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) /* source clip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) if ((sx >= info->var.xres_virtual) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) (sy >= info->var.yres_virtual))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) /* source Area not within virtual screen, skipping */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) if ((sx + width) >= info->var.xres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) width = info->var.xres_virtual - sx - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) if ((sy + height) >= info->var.yres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) height = info->var.yres_virtual - sy - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) /* dest clip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) if ((dx >= info->var.xres_virtual) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) (dy >= info->var.yres_virtual))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) /* Destination Area not within virtual screen, skipping */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) if ((dx + width) >= info->var.xres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) width = info->var.xres_virtual - dx - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) if ((dy + height) >= info->var.yres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) height = info->var.yres_virtual - dy - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) if ((sx < dx) || (sy < dy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) rtl = 1 << 27;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) sx += width - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) dx += width - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) sy += height - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) dy += height - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) if (sm501fb_sync(info))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) /* set the base addresses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) smc501_writel(par->screen.sm_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) fbi->regs2d + SM501_2D_DESTINATION_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) /* set the window width */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) smc501_writel((info->var.xres << 16) | info->var.xres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) fbi->regs2d + SM501_2D_WINDOW_WIDTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) /* set window stride */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) fbi->regs2d + SM501_2D_PITCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) /* set data format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) /* 2d compare mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) /* 2d mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) /* source and destination x y */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) smc501_writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) smc501_writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) /* w/h */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) /* do area move */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) smc501_writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) struct sm501fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) struct sm501fb_info *fbi = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) int width = rect->width, height = rect->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) if ((rect->dx >= info->var.xres_virtual) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) (rect->dy >= info->var.yres_virtual))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) /* Rectangle not within virtual screen, skipping */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) if ((rect->dx + width) >= info->var.xres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) width = info->var.xres_virtual - rect->dx - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) if ((rect->dy + height) >= info->var.yres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) height = info->var.yres_virtual - rect->dy - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) if (sm501fb_sync(info))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) /* set the base addresses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) smc501_writel(par->screen.sm_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) fbi->regs2d + SM501_2D_DESTINATION_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) /* set the window width */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) smc501_writel((info->var.xres << 16) | info->var.xres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) fbi->regs2d + SM501_2D_WINDOW_WIDTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) /* set window stride */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) fbi->regs2d + SM501_2D_PITCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) /* set data format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) /* 2d compare mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) /* 2d mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) /* colour */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) smc501_writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) /* x y */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) smc501_writel((rect->dx << 16) | rect->dy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) fbi->regs2d + SM501_2D_DESTINATION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) /* w/h */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) /* do rectangle fill */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) smc501_writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) }
^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) static struct fb_ops sm501fb_ops_crt = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) .fb_check_var = sm501fb_check_var_crt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) .fb_set_par = sm501fb_set_par_crt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) .fb_blank = sm501fb_blank_crt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) .fb_setcolreg = sm501fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) .fb_pan_display = sm501fb_pan_crt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) .fb_cursor = sm501fb_cursor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) .fb_fillrect = sm501fb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) .fb_copyarea = sm501fb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) .fb_sync = sm501fb_sync,
^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) static struct fb_ops sm501fb_ops_pnl = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) .fb_check_var = sm501fb_check_var_pnl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) .fb_set_par = sm501fb_set_par_pnl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) .fb_pan_display = sm501fb_pan_pnl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) .fb_blank = sm501fb_blank_pnl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) .fb_setcolreg = sm501fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) .fb_cursor = sm501fb_cursor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) .fb_fillrect = sm501fb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) .fb_copyarea = sm501fb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) .fb_sync = sm501fb_sync,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) /* sm501_init_cursor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) * initialise hw cursor parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) struct sm501fb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) struct sm501fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) if (fbi == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) par = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) info = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) par->cursor_regs = info->regs + reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) fbi->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) /* initialise the colour registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) smc501_writel(par->cursor.sm_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) par->cursor_regs + SM501_OFF_HWC_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) sm501fb_sync_regs(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) /* sm501fb_info_start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) * fills the par structure claiming resources and remapping etc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) static int sm501fb_start(struct sm501fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) int k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) info->irq = ret = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) /* we currently do not use the IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) dev_warn(dev, "no irq for device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) /* allocate, reserve and remap resources for display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) * controller registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) if (res == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) dev_err(dev, "no resource definition for registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) goto err_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) info->regs_res = request_mem_region(res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) resource_size(res),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) pdev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) if (info->regs_res == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) dev_err(dev, "cannot claim registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) goto err_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) info->regs = ioremap(res->start, resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) if (info->regs == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) dev_err(dev, "cannot remap registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) goto err_regs_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) /* allocate, reserve and remap resources for 2d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) * controller registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) if (res == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) dev_err(dev, "no resource definition for 2d registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) goto err_regs_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) info->regs2d_res = request_mem_region(res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) resource_size(res),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) pdev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) if (info->regs2d_res == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) dev_err(dev, "cannot claim registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) goto err_regs_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) info->regs2d = ioremap(res->start, resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) if (info->regs2d == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) dev_err(dev, "cannot remap registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) goto err_regs2d_res;
^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) /* allocate, reserve resources for framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) if (res == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) dev_err(dev, "no memory resource defined\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) goto err_regs2d_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) info->fbmem_res = request_mem_region(res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) resource_size(res),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) pdev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) if (info->fbmem_res == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) dev_err(dev, "cannot claim framebuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) goto err_regs2d_map;
^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) info->fbmem = ioremap(res->start, resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) if (info->fbmem == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) dev_err(dev, "cannot remap framebuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) goto err_mem_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) info->fbmem_len = resource_size(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) /* clear framebuffer memory - avoids garbage data on unused fb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) memset_io(info->fbmem, 0, info->fbmem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) /* clear palette ram - undefined at power on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) for (k = 0; k < (256 * 3); k++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) smc501_writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) /* enable display controller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) /* enable 2d controller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) sm501_unit_power(dev->parent, SM501_GATE_2D_ENGINE, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) /* setup cursors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) return 0; /* everything is setup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) err_mem_res:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) release_mem_region(info->fbmem_res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) resource_size(info->fbmem_res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) err_regs2d_map:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) iounmap(info->regs2d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) err_regs2d_res:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) release_mem_region(info->regs2d_res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) resource_size(info->regs2d_res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) err_regs_map:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) iounmap(info->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) err_regs_res:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) release_mem_region(info->regs_res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) resource_size(info->regs_res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) err_release:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) static void sm501fb_stop(struct sm501fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) /* disable display controller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) iounmap(info->fbmem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) release_mem_region(info->fbmem_res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) resource_size(info->fbmem_res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) iounmap(info->regs2d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) release_mem_region(info->regs2d_res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) resource_size(info->regs2d_res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) iounmap(info->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) release_mem_region(info->regs_res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) resource_size(info->regs_res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) static int sm501fb_init_fb(struct fb_info *fb, enum sm501_controller head,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) const char *fbname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) struct sm501_platdata_fbsub *pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) struct sm501fb_par *par = fb->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) struct sm501fb_info *info = par->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) unsigned long ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) unsigned int enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) switch (head) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) case HEAD_CRT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) pd = info->pdata->fb_crt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) /* ensure we set the correct source register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) if (info->pdata->fb_route != SM501_FB_CRT_PANEL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) ctrl |= SM501_DC_CRT_CONTROL_SEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) case HEAD_PANEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) pd = info->pdata->fb_pnl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) ctrl = smc501_readl(info->regs + SM501_DC_PANEL_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) pd = NULL; /* stop compiler warnings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) ctrl = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) enable = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) BUG();
^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) dev_info(info->dev, "fb %s %sabled at start\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) fbname, enable ? "en" : "dis");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) /* check to see if our routing allows this */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) enable = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) strlcpy(fb->fix.id, fbname, sizeof(fb->fix.id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) memcpy(&par->ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) sizeof(struct fb_ops));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) /* update ops dependent on what we've been passed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) par->ops.fb_cursor = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) fb->fbops = &par->ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) fb->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) #if defined(CONFIG_OF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) #ifdef __BIG_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) if (of_get_property(info->dev->parent->of_node, "little-endian", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) fb->flags |= FBINFO_FOREIGN_ENDIAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) if (of_get_property(info->dev->parent->of_node, "big-endian", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) fb->flags |= FBINFO_FOREIGN_ENDIAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) /* fixed data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) fb->fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) fb->fix.type_aux = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) fb->fix.xpanstep = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) fb->fix.ypanstep = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) fb->fix.ywrapstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) fb->fix.accel = FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) /* screenmode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) fb->var.nonstd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) fb->var.activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) fb->var.accel_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) fb->var.vmode = FB_VMODE_NONINTERLACED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) fb->var.bits_per_pixel = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) if (info->edid_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) /* Now build modedb from EDID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) fb_edid_to_monspecs(info->edid_data, &fb->monspecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) fb_videomode_to_modelist(fb->monspecs.modedb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) fb->monspecs.modedb_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) &fb->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) /* TODO read the mode from the current display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) if (pd->def_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) dev_info(info->dev, "using supplied mode\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) fb_videomode_to_var(&fb->var, pd->def_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) fb->var.bits_per_pixel = pd->def_bpp ? pd->def_bpp : 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) fb->var.xres_virtual = fb->var.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) fb->var.yres_virtual = fb->var.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) if (info->edid_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) ret = fb_find_mode(&fb->var, fb, fb_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) fb->monspecs.modedb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) fb->monspecs.modedb_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) &sm501_default_mode, default_bpp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) /* edid_data is no longer needed, free it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) kfree(info->edid_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) ret = fb_find_mode(&fb->var, fb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) NULL, NULL, 0, NULL, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) switch (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) dev_info(info->dev, "using mode specified in "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) "@mode\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) dev_info(info->dev, "using mode specified in "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) "@mode with ignored refresh rate\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) dev_info(info->dev, "using mode default "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) "mode\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) dev_info(info->dev, "using mode from list\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) dev_info(info->dev, "ret = %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) dev_info(info->dev, "failed to find mode\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) /* initialise and set the palette */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) if (fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) dev_err(info->dev, "failed to allocate cmap memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) fb_set_cmap(&fb->cmap, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) ret = (fb->fbops->fb_check_var)(&fb->var, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) dev_err(info->dev, "check_var() failed on initial setup?\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) /* default platform data if none is supplied (ie, PCI device) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) static struct sm501_platdata_fbsub sm501fb_pdata_crt = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) .flags = (SM501FB_FLAG_USE_INIT_MODE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) SM501FB_FLAG_USE_HWCURSOR |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) SM501FB_FLAG_USE_HWACCEL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) SM501FB_FLAG_DISABLE_AT_EXIT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) static struct sm501_platdata_fbsub sm501fb_pdata_pnl = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) .flags = (SM501FB_FLAG_USE_INIT_MODE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) SM501FB_FLAG_USE_HWCURSOR |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) SM501FB_FLAG_USE_HWACCEL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) SM501FB_FLAG_DISABLE_AT_EXIT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) static struct sm501_platdata_fb sm501fb_def_pdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) .fb_route = SM501_FB_OWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) .fb_crt = &sm501fb_pdata_crt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) .fb_pnl = &sm501fb_pdata_pnl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) static char driver_name_crt[] = "sm501fb-crt";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) static char driver_name_pnl[] = "sm501fb-panel";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) static int sm501fb_probe_one(struct sm501fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) enum sm501_controller head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) struct sm501_platdata_fbsub *pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) struct sm501fb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) struct fb_info *fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) /* Do not initialise if we've not been given any platform data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) if (pd == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) dev_info(info->dev, "no data for fb %s (disabled)\n", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) if (!fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) par = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) par->info = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) par->head = head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) fbi->pseudo_palette = &par->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) info->fb[head] = fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) /* Free up anything allocated by sm501fb_init_fb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) static void sm501_free_init_fb(struct sm501fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) enum sm501_controller head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) struct fb_info *fbi = info->fb[head];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) if (!fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) fb_dealloc_cmap(&fbi->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) static int sm501fb_start_one(struct sm501fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) enum sm501_controller head, const char *drvname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) struct fb_info *fbi = info->fb[head];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) if (!fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) mutex_init(&info->fb[head]->mm_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) ret = sm501fb_init_fb(info->fb[head], head, drvname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) dev_err(info->dev, "cannot initialise fb %s\n", drvname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) ret = register_framebuffer(info->fb[head]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) dev_err(info->dev, "failed to register fb %s\n", drvname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) sm501_free_init_fb(info, head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) static int sm501fb_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) struct sm501fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) /* allocate our framebuffers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) info = kzalloc(sizeof(*info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) dev_err(dev, "failed to allocate state\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) info->dev = dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) platform_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947) if (dev->parent->platform_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) struct sm501_platdata *pd = dev->parent->platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) info->pdata = pd->fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) if (info->pdata == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) int found = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) #if defined(CONFIG_OF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) struct device_node *np = pdev->dev.parent->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956) const u8 *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) const char *cp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) info->pdata = &sm501fb_def_pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) if (np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) /* Get EDID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) cp = of_get_property(np, "mode", &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) if (cp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965) strcpy(fb_mode, cp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) prop = of_get_property(np, "edid", &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) if (prop && len == EDID_LENGTH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) info->edid_data = kmemdup(prop, EDID_LENGTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) if (info->edid_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) found = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) if (!found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) dev_info(dev, "using default configuration data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977) info->pdata = &sm501fb_def_pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) /* probe for the presence of each panel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983) ret = sm501fb_probe_one(info, HEAD_CRT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985) dev_err(dev, "failed to probe CRT\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) goto err_alloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989) ret = sm501fb_probe_one(info, HEAD_PANEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991) dev_err(dev, "failed to probe PANEL\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) goto err_probed_crt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) if (info->fb[HEAD_PANEL] == NULL &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996) info->fb[HEAD_CRT] == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) dev_err(dev, "no framebuffers found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999) goto err_alloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) /* get the resources for both of the framebuffers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004) ret = sm501fb_start(info, pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006) dev_err(dev, "cannot initialise SM501\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) goto err_probed_panel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010) ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012) dev_err(dev, "failed to start CRT\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013) goto err_started;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016) ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) dev_err(dev, "failed to start Panel\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019) goto err_started_crt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022) /* we registered, return ok */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025) err_started_crt:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026) unregister_framebuffer(info->fb[HEAD_CRT]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027) sm501_free_init_fb(info, HEAD_CRT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029) err_started:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030) sm501fb_stop(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032) err_probed_panel:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) framebuffer_release(info->fb[HEAD_PANEL]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035) err_probed_crt:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) framebuffer_release(info->fb[HEAD_CRT]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038) err_alloc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046) * Cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048) static int sm501fb_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) struct sm501fb_info *info = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051) struct fb_info *fbinfo_crt = info->fb[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052) struct fb_info *fbinfo_pnl = info->fb[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054) sm501_free_init_fb(info, HEAD_CRT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055) sm501_free_init_fb(info, HEAD_PANEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057) if (fbinfo_crt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058) unregister_framebuffer(fbinfo_crt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059) if (fbinfo_pnl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060) unregister_framebuffer(fbinfo_pnl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062) sm501fb_stop(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065) framebuffer_release(fbinfo_pnl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066) framebuffer_release(fbinfo_crt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073) static int sm501fb_suspend_fb(struct sm501fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074) enum sm501_controller head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2075) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2076) struct fb_info *fbi = info->fb[head];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2077) struct sm501fb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2079) if (!fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2080) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2081)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2082) par = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2083) if (par->screen.size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2084) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2085)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2086) /* blank the relevant interface to ensure unit power minimised */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2087) (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2089) /* tell console/fb driver we are suspending */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2091) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2092) fb_set_suspend(fbi, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2093) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2095) /* backup copies in case chip is powered down over suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2097) par->store_fb = vmalloc(par->screen.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2098) if (par->store_fb == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2099) dev_err(info->dev, "no memory to store screen\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2100) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2103) par->store_cursor = vmalloc(par->cursor.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2104) if (par->store_cursor == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2105) dev_err(info->dev, "no memory to store cursor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2106) goto err_nocursor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2109) dev_dbg(info->dev, "suspending screen to %p\n", par->store_fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2110) dev_dbg(info->dev, "suspending cursor to %p\n", par->store_cursor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2112) memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2113) memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2115) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2117) err_nocursor:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2118) vfree(par->store_fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2119) par->store_fb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2121) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2124) static void sm501fb_resume_fb(struct sm501fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2125) enum sm501_controller head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2127) struct fb_info *fbi = info->fb[head];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2128) struct sm501fb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2130) if (!fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2131) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2133) par = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2134) if (par->screen.size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2135) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2137) /* re-activate the configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2139) (par->ops.fb_set_par)(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2141) /* restore the data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2143) dev_dbg(info->dev, "restoring screen from %p\n", par->store_fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2144) dev_dbg(info->dev, "restoring cursor from %p\n", par->store_cursor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2146) if (par->store_fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2147) memcpy_toio(par->screen.k_addr, par->store_fb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2148) par->screen.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2150) if (par->store_cursor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2151) memcpy_toio(par->cursor.k_addr, par->store_cursor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2152) par->cursor.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2154) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2155) fb_set_suspend(fbi, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2156) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2158) vfree(par->store_fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2159) vfree(par->store_cursor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2163) /* suspend and resume support */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2165) static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2167) struct sm501fb_info *info = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2169) /* store crt control to resume with */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2170) info->pm_crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2172) sm501fb_suspend_fb(info, HEAD_CRT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2173) sm501fb_suspend_fb(info, HEAD_PANEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2175) /* turn off the clocks, in case the device is not powered down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2176) sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2178) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2181) #define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2182) SM501_DC_CRT_CONTROL_SEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2185) static int sm501fb_resume(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2187) struct sm501fb_info *info = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2188) unsigned long crt_ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2190) sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2192) /* restore the items we want to be saved for crt control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2194) crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2195) crt_ctrl &= ~SM501_CRT_CTRL_SAVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2196) crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2197) smc501_writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2199) sm501fb_resume_fb(info, HEAD_CRT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2200) sm501fb_resume_fb(info, HEAD_PANEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2202) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2205) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2206) #define sm501fb_suspend NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2207) #define sm501fb_resume NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2208) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2210) static struct platform_driver sm501fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2211) .probe = sm501fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2212) .remove = sm501fb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2213) .suspend = sm501fb_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2214) .resume = sm501fb_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2215) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2216) .name = "sm501-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2217) .dev_groups = sm501fb_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2218) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2219) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2221) module_platform_driver(sm501fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2223) module_param_named(mode, fb_mode, charp, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2224) MODULE_PARM_DESC(mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2225) "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2226) module_param_named(bpp, default_bpp, ulong, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2227) MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2228) MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2229) MODULE_DESCRIPTION("SM501 Framebuffer driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2230) MODULE_LICENSE("GPL v2");