cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

carminefb.c (22583B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Frame buffer driver for the Carmine GPU.
      4 *
      5 * The driver configures the GPU as follows
      6 * - FB0 is display 0 with unique memory area
      7 * - FB1 is display 1 with unique memory area
      8 * - both display use 32 bit colors
      9 */
     10#include <linux/delay.h>
     11#include <linux/errno.h>
     12#include <linux/fb.h>
     13#include <linux/interrupt.h>
     14#include <linux/pci.h>
     15#include <linux/slab.h>
     16#include <linux/module.h>
     17
     18#include "carminefb.h"
     19#include "carminefb_regs.h"
     20
     21#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
     22#error  "The endianness of the target host has not been defined."
     23#endif
     24
     25/*
     26 * The initial video mode can be supplied via two different ways:
     27 * - as a string that is passed to fb_find_mode() (module option fb_mode_str)
     28 * - as an integer that picks the video mode from carmine_modedb[] (module
     29 *   option fb_mode)
     30 *
     31 * If nothing is used than the initial video mode will be the
     32 * CARMINEFB_DEFAULT_VIDEO_MODE member of the carmine_modedb[].
     33 */
     34#define CARMINEFB_DEFAULT_VIDEO_MODE	1
     35
     36static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
     37module_param(fb_mode, uint, 0444);
     38MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
     39
     40static char *fb_mode_str;
     41module_param(fb_mode_str, charp, 0444);
     42MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
     43
     44/*
     45 * Carminefb displays:
     46 * 0b000 None
     47 * 0b001 Display 0
     48 * 0b010 Display 1
     49 */
     50static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
     51module_param(fb_displays, int, 0444);
     52MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
     53
     54struct carmine_hw {
     55	void __iomem *v_regs;
     56	void __iomem *screen_mem;
     57	struct fb_info *fb[MAX_DISPLAY];
     58};
     59
     60struct carmine_resolution {
     61	u32 htp;
     62	u32 hsp;
     63	u32 hsw;
     64	u32 hdp;
     65	u32 vtr;
     66	u32 vsp;
     67	u32 vsw;
     68	u32 vdp;
     69	u32 disp_mode;
     70};
     71
     72struct carmine_fb {
     73	void __iomem *display_reg;
     74	void __iomem *screen_base;
     75	u32 smem_offset;
     76	u32 cur_mode;
     77	u32 new_mode;
     78	struct carmine_resolution *res;
     79	u32 pseudo_palette[16];
     80};
     81
     82static struct fb_fix_screeninfo carminefb_fix = {
     83	.id = "Carmine",
     84	.type = FB_TYPE_PACKED_PIXELS,
     85	.visual = FB_VISUAL_TRUECOLOR,
     86	.accel = FB_ACCEL_NONE,
     87};
     88
     89static const struct fb_videomode carmine_modedb[] = {
     90	{
     91		.name		= "640x480",
     92		.xres		= 640,
     93		.yres		= 480,
     94	}, {
     95		.name		= "800x600",
     96		.xres		= 800,
     97		.yres		= 600,
     98	},
     99};
    100
    101static struct carmine_resolution car_modes[] = {
    102	{
    103		/* 640x480 */
    104		.htp = 800,
    105		.hsp = 672,
    106		.hsw = 96,
    107		.hdp = 640,
    108		.vtr = 525,
    109		.vsp = 490,
    110		.vsw = 2,
    111		.vdp = 480,
    112		.disp_mode = 0x1400,
    113	},
    114	{
    115		/* 800x600 */
    116		.htp = 1060,
    117		.hsp = 864,
    118		.hsw = 72,
    119		.hdp = 800,
    120		.vtr = 628,
    121		.vsp = 601,
    122		.vsw = 2,
    123		.vdp = 600,
    124		.disp_mode = 0x0d00,
    125	}
    126};
    127
    128static int carmine_find_mode(const struct fb_var_screeninfo *var)
    129{
    130	int i;
    131
    132	for (i = 0; i < ARRAY_SIZE(car_modes); i++)
    133		if (car_modes[i].hdp == var->xres &&
    134		    car_modes[i].vdp == var->yres)
    135			return i;
    136	return -EINVAL;
    137}
    138
    139static void c_set_disp_reg(const struct carmine_fb *par,
    140		u32 offset, u32 val)
    141{
    142	writel(val, par->display_reg + offset);
    143}
    144
    145static u32 c_get_disp_reg(const struct carmine_fb *par,
    146		u32 offset)
    147{
    148	return readl(par->display_reg + offset);
    149}
    150
    151static void c_set_hw_reg(const struct carmine_hw *hw,
    152		u32 offset, u32 val)
    153{
    154	writel(val, hw->v_regs + offset);
    155}
    156
    157static u32 c_get_hw_reg(const struct carmine_hw *hw,
    158		u32 offset)
    159{
    160	return readl(hw->v_regs + offset);
    161}
    162
    163static int carmine_setcolreg(unsigned regno, unsigned red, unsigned green,
    164		unsigned blue, unsigned transp, struct fb_info *info)
    165{
    166	if (regno >= 16)
    167		return 1;
    168
    169	red >>= 8;
    170	green >>= 8;
    171	blue >>= 8;
    172	transp >>= 8;
    173
    174	((__be32 *)info->pseudo_palette)[regno] = cpu_to_be32(transp << 24 |
    175		red << 0 | green << 8 | blue << 16);
    176	return 0;
    177}
    178
    179static int carmine_check_var(struct fb_var_screeninfo *var,
    180		struct fb_info *info)
    181{
    182	int ret;
    183
    184	ret = carmine_find_mode(var);
    185	if (ret < 0)
    186		return ret;
    187
    188	if (var->grayscale || var->rotate || var->nonstd)
    189		return -EINVAL;
    190
    191	var->xres_virtual = var->xres;
    192	var->yres_virtual = var->yres;
    193
    194	var->bits_per_pixel = 32;
    195
    196#ifdef __BIG_ENDIAN
    197	var->transp.offset = 24;
    198	var->red.offset = 0;
    199	var->green.offset = 8;
    200	var->blue.offset = 16;
    201#else
    202	var->transp.offset = 24;
    203	var->red.offset = 16;
    204	var->green.offset = 8;
    205	var->blue.offset = 0;
    206#endif
    207
    208	var->red.length = 8;
    209	var->green.length = 8;
    210	var->blue.length = 8;
    211	var->transp.length = 8;
    212
    213	var->red.msb_right = 0;
    214	var->green.msb_right = 0;
    215	var->blue.msb_right = 0;
    216	var->transp.msb_right = 0;
    217	return 0;
    218}
    219
    220static void carmine_init_display_param(struct carmine_fb *par)
    221{
    222	u32 width;
    223	u32 height;
    224	u32 param;
    225	u32 window_size;
    226	u32 soffset = par->smem_offset;
    227
    228	c_set_disp_reg(par, CARMINE_DISP_REG_C_TRANS, 0);
    229	c_set_disp_reg(par, CARMINE_DISP_REG_MLMR_TRANS, 0);
    230	c_set_disp_reg(par, CARMINE_DISP_REG_CURSOR_MODE,
    231			CARMINE_CURSOR0_PRIORITY_MASK |
    232			CARMINE_CURSOR1_PRIORITY_MASK |
    233			CARMINE_CURSOR_CUTZ_MASK);
    234
    235	/* Set default cursor position */
    236	c_set_disp_reg(par, CARMINE_DISP_REG_CUR1_POS, 0 << 16 | 0);
    237	c_set_disp_reg(par, CARMINE_DISP_REG_CUR2_POS, 0 << 16 | 0);
    238
    239	/* Set default display mode */
    240	c_set_disp_reg(par, CARMINE_DISP_REG_L0_EXT_MODE, CARMINE_WINDOW_MODE |
    241			CARMINE_EXT_CMODE_DIRECT24_RGBA);
    242	c_set_disp_reg(par, CARMINE_DISP_REG_L1_EXT_MODE,
    243			CARMINE_EXT_CMODE_DIRECT24_RGBA);
    244	c_set_disp_reg(par, CARMINE_DISP_REG_L2_EXT_MODE, CARMINE_EXTEND_MODE |
    245			CARMINE_EXT_CMODE_DIRECT24_RGBA);
    246	c_set_disp_reg(par, CARMINE_DISP_REG_L3_EXT_MODE, CARMINE_EXTEND_MODE |
    247			CARMINE_EXT_CMODE_DIRECT24_RGBA);
    248	c_set_disp_reg(par, CARMINE_DISP_REG_L4_EXT_MODE, CARMINE_EXTEND_MODE |
    249			CARMINE_EXT_CMODE_DIRECT24_RGBA);
    250	c_set_disp_reg(par, CARMINE_DISP_REG_L5_EXT_MODE, CARMINE_EXTEND_MODE |
    251			CARMINE_EXT_CMODE_DIRECT24_RGBA);
    252	c_set_disp_reg(par, CARMINE_DISP_REG_L6_EXT_MODE, CARMINE_EXTEND_MODE |
    253			CARMINE_EXT_CMODE_DIRECT24_RGBA);
    254	c_set_disp_reg(par, CARMINE_DISP_REG_L7_EXT_MODE, CARMINE_EXTEND_MODE |
    255			CARMINE_EXT_CMODE_DIRECT24_RGBA);
    256
    257	/* Set default frame size to layer mode register */
    258	width = par->res->hdp * 4 / CARMINE_DISP_WIDTH_UNIT;
    259	width = width << CARMINE_DISP_WIDTH_SHIFT;
    260
    261	height = par->res->vdp - 1;
    262	param = width | height;
    263
    264	c_set_disp_reg(par, CARMINE_DISP_REG_L0_MODE_W_H, param);
    265	c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIDTH, width);
    266	c_set_disp_reg(par, CARMINE_DISP_REG_L2_MODE_W_H, param);
    267	c_set_disp_reg(par, CARMINE_DISP_REG_L3_MODE_W_H, param);
    268	c_set_disp_reg(par, CARMINE_DISP_REG_L4_MODE_W_H, param);
    269	c_set_disp_reg(par, CARMINE_DISP_REG_L5_MODE_W_H, param);
    270	c_set_disp_reg(par, CARMINE_DISP_REG_L6_MODE_W_H, param);
    271	c_set_disp_reg(par, CARMINE_DISP_REG_L7_MODE_W_H, param);
    272
    273	/* Set default pos and size */
    274	window_size = (par->res->vdp - 1) << CARMINE_DISP_WIN_H_SHIFT;
    275	window_size |= par->res->hdp;
    276
    277	c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_POS, 0);
    278	c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_SIZE, window_size);
    279	c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_POS, 0);
    280	c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_SIZE, window_size);
    281	c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_POS, 0);
    282	c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_SIZE, window_size);
    283	c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_POS, 0);
    284	c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_SIZE, window_size);
    285	c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_POS, 0);
    286	c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_SIZE, window_size);
    287	c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_POS, 0);
    288	c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_SIZE, window_size);
    289	c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_POS, 0);
    290	c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_SIZE, window_size);
    291	c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_POS, 0);
    292	c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_SIZE, window_size);
    293
    294	/* Set default origin address */
    295	c_set_disp_reg(par, CARMINE_DISP_REG_L0_ORG_ADR, soffset);
    296	c_set_disp_reg(par, CARMINE_DISP_REG_L1_ORG_ADR, soffset);
    297	c_set_disp_reg(par, CARMINE_DISP_REG_L2_ORG_ADR1, soffset);
    298	c_set_disp_reg(par, CARMINE_DISP_REG_L3_ORG_ADR1, soffset);
    299	c_set_disp_reg(par, CARMINE_DISP_REG_L4_ORG_ADR1, soffset);
    300	c_set_disp_reg(par, CARMINE_DISP_REG_L5_ORG_ADR1, soffset);
    301	c_set_disp_reg(par, CARMINE_DISP_REG_L6_ORG_ADR1, soffset);
    302	c_set_disp_reg(par, CARMINE_DISP_REG_L7_ORG_ADR1, soffset);
    303
    304	/* Set default display address */
    305	c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_ADR, soffset);
    306	c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_ADR1, soffset);
    307	c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_ADR1, soffset);
    308	c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_ADR1, soffset);
    309	c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_ADR1, soffset);
    310	c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_ADR0, soffset);
    311	c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_ADR0, soffset);
    312
    313	/* Set default display position */
    314	c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_POS, 0);
    315	c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_POS, 0);
    316	c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_POS, 0);
    317	c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_POS, 0);
    318	c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_POS, 0);
    319	c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_POS, 0);
    320	c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_POS, 0);
    321
    322	/* Set default blend mode */
    323	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L0, 0);
    324	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L1, 0);
    325	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L2, 0);
    326	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L3, 0);
    327	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L4, 0);
    328	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L5, 0);
    329	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L6, 0);
    330	c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L7, 0);
    331
    332	/* default transparency mode */
    333	c_set_disp_reg(par, CARMINE_DISP_REG_L0_TRANS, 0);
    334	c_set_disp_reg(par, CARMINE_DISP_REG_L1_TRANS, 0);
    335	c_set_disp_reg(par, CARMINE_DISP_REG_L2_TRANS, 0);
    336	c_set_disp_reg(par, CARMINE_DISP_REG_L3_TRANS, 0);
    337	c_set_disp_reg(par, CARMINE_DISP_REG_L4_TRANS, 0);
    338	c_set_disp_reg(par, CARMINE_DISP_REG_L5_TRANS, 0);
    339	c_set_disp_reg(par, CARMINE_DISP_REG_L6_TRANS, 0);
    340	c_set_disp_reg(par, CARMINE_DISP_REG_L7_TRANS, 0);
    341
    342	/* Set default read skip parameter */
    343	c_set_disp_reg(par, CARMINE_DISP_REG_L0RM, 0);
    344	c_set_disp_reg(par, CARMINE_DISP_REG_L2RM, 0);
    345	c_set_disp_reg(par, CARMINE_DISP_REG_L3RM, 0);
    346	c_set_disp_reg(par, CARMINE_DISP_REG_L4RM, 0);
    347	c_set_disp_reg(par, CARMINE_DISP_REG_L5RM, 0);
    348	c_set_disp_reg(par, CARMINE_DISP_REG_L6RM, 0);
    349	c_set_disp_reg(par, CARMINE_DISP_REG_L7RM, 0);
    350
    351	c_set_disp_reg(par, CARMINE_DISP_REG_L0PX, 0);
    352	c_set_disp_reg(par, CARMINE_DISP_REG_L2PX, 0);
    353	c_set_disp_reg(par, CARMINE_DISP_REG_L3PX, 0);
    354	c_set_disp_reg(par, CARMINE_DISP_REG_L4PX, 0);
    355	c_set_disp_reg(par, CARMINE_DISP_REG_L5PX, 0);
    356	c_set_disp_reg(par, CARMINE_DISP_REG_L6PX, 0);
    357	c_set_disp_reg(par, CARMINE_DISP_REG_L7PX, 0);
    358
    359	c_set_disp_reg(par, CARMINE_DISP_REG_L0PY, 0);
    360	c_set_disp_reg(par, CARMINE_DISP_REG_L2PY, 0);
    361	c_set_disp_reg(par, CARMINE_DISP_REG_L3PY, 0);
    362	c_set_disp_reg(par, CARMINE_DISP_REG_L4PY, 0);
    363	c_set_disp_reg(par, CARMINE_DISP_REG_L5PY, 0);
    364	c_set_disp_reg(par, CARMINE_DISP_REG_L6PY, 0);
    365	c_set_disp_reg(par, CARMINE_DISP_REG_L7PY, 0);
    366}
    367
    368static void set_display_parameters(struct carmine_fb *par)
    369{
    370	u32 mode;
    371	u32 hdp, vdp, htp, hsp, hsw, vtr, vsp, vsw;
    372
    373	/*
    374	 * display timing. Parameters are decreased by one because hardware
    375	 * spec is 0 to (n - 1)
    376	 * */
    377	hdp = par->res->hdp - 1;
    378	vdp = par->res->vdp - 1;
    379	htp = par->res->htp - 1;
    380	hsp = par->res->hsp - 1;
    381	hsw = par->res->hsw - 1;
    382	vtr = par->res->vtr - 1;
    383	vsp = par->res->vsp - 1;
    384	vsw = par->res->vsw - 1;
    385
    386	c_set_disp_reg(par, CARMINE_DISP_REG_H_TOTAL,
    387			htp << CARMINE_DISP_HTP_SHIFT);
    388	c_set_disp_reg(par, CARMINE_DISP_REG_H_PERIOD,
    389			(hdp << CARMINE_DISP_HDB_SHIFT)	| hdp);
    390	c_set_disp_reg(par, CARMINE_DISP_REG_V_H_W_H_POS,
    391			(vsw << CARMINE_DISP_VSW_SHIFT) |
    392			(hsw << CARMINE_DISP_HSW_SHIFT) |
    393			(hsp));
    394	c_set_disp_reg(par, CARMINE_DISP_REG_V_TOTAL,
    395			vtr << CARMINE_DISP_VTR_SHIFT);
    396	c_set_disp_reg(par, CARMINE_DISP_REG_V_PERIOD_POS,
    397			(vdp << CARMINE_DISP_VDP_SHIFT) | vsp);
    398
    399	/* clock */
    400	mode = c_get_disp_reg(par, CARMINE_DISP_REG_DCM1);
    401	mode = (mode & ~CARMINE_DISP_DCM_MASK) |
    402		(par->res->disp_mode & CARMINE_DISP_DCM_MASK);
    403	/* enable video output and layer 0 */
    404	mode |= CARMINE_DEN | CARMINE_L0E;
    405	c_set_disp_reg(par, CARMINE_DISP_REG_DCM1, mode);
    406}
    407
    408static int carmine_set_par(struct fb_info *info)
    409{
    410	struct carmine_fb *par = info->par;
    411	int ret;
    412
    413	ret = carmine_find_mode(&info->var);
    414	if (ret < 0)
    415		return ret;
    416
    417	par->new_mode = ret;
    418	if (par->cur_mode != par->new_mode) {
    419
    420		par->cur_mode = par->new_mode;
    421		par->res = &car_modes[par->new_mode];
    422
    423		carmine_init_display_param(par);
    424		set_display_parameters(par);
    425	}
    426
    427	info->fix.line_length = info->var.xres * info->var.bits_per_pixel / 8;
    428	return 0;
    429}
    430
    431static int init_hardware(struct carmine_hw *hw)
    432{
    433	u32 flags;
    434	u32 loops;
    435	u32 ret;
    436
    437	/* Initialize Carmine */
    438	/* Sets internal clock */
    439	c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE,
    440			CARMINE_DFLT_IP_CLOCK_ENABLE);
    441
    442	/* Video signal output is turned off */
    443	c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
    444	c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
    445
    446	/* Software reset */
    447	c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 1);
    448	c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 0);
    449
    450	/* I/O mode settings */
    451	flags = CARMINE_DFLT_IP_DCTL_IO_CONT1 << 16 |
    452		CARMINE_DFLT_IP_DCTL_IO_CONT0;
    453	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_IOCONT1_IOCONT0,
    454			flags);
    455
    456	/* DRAM initial sequence */
    457	flags = CARMINE_DFLT_IP_DCTL_MODE << 16 | CARMINE_DFLT_IP_DCTL_ADD;
    458	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD,
    459			flags);
    460
    461	flags = CARMINE_DFLT_IP_DCTL_SET_TIME1 << 16 |
    462		CARMINE_DFLT_IP_DCTL_EMODE;
    463	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_SETTIME1_EMODE,
    464			flags);
    465
    466	flags = CARMINE_DFLT_IP_DCTL_REFRESH << 16 |
    467		CARMINE_DFLT_IP_DCTL_SET_TIME2;
    468	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_REFRESH_SETTIME2,
    469			flags);
    470
    471	flags = CARMINE_DFLT_IP_DCTL_RESERVE2 << 16 |
    472		CARMINE_DFLT_IP_DCTL_FIFO_DEPTH;
    473	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV2_RSV1, flags);
    474
    475	flags = CARMINE_DFLT_IP_DCTL_DDRIF2 << 16 | CARMINE_DFLT_IP_DCTL_DDRIF1;
    476	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_DDRIF2_DDRIF1,
    477			flags);
    478
    479	flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
    480		CARMINE_DFLT_IP_DCTL_STATES;
    481	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
    482			flags);
    483
    484	/* Executes DLL reset */
    485	if (CARMINE_DCTL_DLL_RESET) {
    486		for (loops = 0; loops < CARMINE_DCTL_INIT_WAIT_LIMIT; loops++) {
    487
    488			ret = c_get_hw_reg(hw, CARMINE_DCTL_REG +
    489					CARMINE_DCTL_REG_RSV0_STATES);
    490			ret &= CARMINE_DCTL_REG_STATES_MASK;
    491			if (!ret)
    492				break;
    493
    494			mdelay(CARMINE_DCTL_INIT_WAIT_INTERVAL);
    495		}
    496
    497		if (loops >= CARMINE_DCTL_INIT_WAIT_LIMIT) {
    498			printk(KERN_ERR "DRAM init failed\n");
    499			return -EIO;
    500		}
    501	}
    502
    503	flags = CARMINE_DFLT_IP_DCTL_MODE_AFT_RST << 16 |
    504		CARMINE_DFLT_IP_DCTL_ADD;
    505	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD, flags);
    506
    507	flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
    508		CARMINE_DFLT_IP_DCTL_STATES_AFT_RST;
    509	c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
    510			flags);
    511
    512	/* Initialize the write back register */
    513	c_set_hw_reg(hw, CARMINE_WB_REG + CARMINE_WB_REG_WBM,
    514			CARMINE_WB_REG_WBM_DEFAULT);
    515
    516	/* Initialize the Kottos registers */
    517	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRINTM, 0);
    518	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRERRM, 0);
    519
    520	/* Set DC offsets */
    521	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PX, 0);
    522	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PY, 0);
    523	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LX, 0);
    524	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LY, 0);
    525	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TX, 0);
    526	c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TY, 0);
    527	return 0;
    528}
    529
    530static const struct fb_ops carminefb_ops = {
    531	.owner		= THIS_MODULE,
    532	.fb_fillrect	= cfb_fillrect,
    533	.fb_copyarea	= cfb_copyarea,
    534	.fb_imageblit	= cfb_imageblit,
    535
    536	.fb_check_var	= carmine_check_var,
    537	.fb_set_par	= carmine_set_par,
    538	.fb_setcolreg	= carmine_setcolreg,
    539};
    540
    541static int alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
    542			    int smem_offset, struct device *device,
    543			    struct fb_info **rinfo)
    544{
    545	int ret;
    546	struct fb_info *info;
    547	struct carmine_fb *par;
    548
    549	info = framebuffer_alloc(sizeof *par, device);
    550	if (!info)
    551		return -ENOMEM;
    552
    553	par = info->par;
    554	par->display_reg = regs;
    555	par->smem_offset = smem_offset;
    556
    557	info->screen_base = smem_base + smem_offset;
    558	info->screen_size = CARMINE_DISPLAY_MEM;
    559	info->fbops = &carminefb_ops;
    560
    561	info->fix = carminefb_fix;
    562	info->pseudo_palette = par->pseudo_palette;
    563	info->flags = FBINFO_DEFAULT;
    564
    565	ret = fb_alloc_cmap(&info->cmap, 256, 1);
    566	if (ret < 0)
    567		goto err_free_fb;
    568
    569	if (fb_mode >= ARRAY_SIZE(carmine_modedb))
    570		fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
    571
    572	par->cur_mode = par->new_mode = ~0;
    573
    574	ret = fb_find_mode(&info->var, info, fb_mode_str, carmine_modedb,
    575			ARRAY_SIZE(carmine_modedb),
    576			&carmine_modedb[fb_mode], 32);
    577	if (!ret || ret == 4) {
    578		ret = -EINVAL;
    579		goto err_dealloc_cmap;
    580	}
    581
    582	fb_videomode_to_modelist(carmine_modedb, ARRAY_SIZE(carmine_modedb),
    583			&info->modelist);
    584
    585	ret = register_framebuffer(info);
    586	if (ret < 0)
    587		goto err_dealloc_cmap;
    588
    589	fb_info(info, "%s frame buffer device\n", info->fix.id);
    590
    591	*rinfo = info;
    592	return 0;
    593
    594err_dealloc_cmap:
    595	fb_dealloc_cmap(&info->cmap);
    596err_free_fb:
    597	framebuffer_release(info);
    598	return ret;
    599}
    600
    601static void cleanup_fb_device(struct fb_info *info)
    602{
    603	if (info) {
    604		unregister_framebuffer(info);
    605		fb_dealloc_cmap(&info->cmap);
    606		framebuffer_release(info);
    607	}
    608}
    609
    610static int carminefb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
    611{
    612	struct carmine_hw *hw;
    613	struct device *device = &dev->dev;
    614	struct fb_info *info;
    615	int ret;
    616
    617	ret = pci_enable_device(dev);
    618	if (ret)
    619		return ret;
    620
    621	ret = -ENOMEM;
    622	hw = kzalloc(sizeof *hw, GFP_KERNEL);
    623	if (!hw)
    624		goto err_enable_pci;
    625
    626	carminefb_fix.mmio_start = pci_resource_start(dev, CARMINE_CONFIG_BAR);
    627	carminefb_fix.mmio_len = pci_resource_len(dev, CARMINE_CONFIG_BAR);
    628
    629	if (!request_mem_region(carminefb_fix.mmio_start,
    630				carminefb_fix.mmio_len,
    631				"carminefb regbase")) {
    632		printk(KERN_ERR "carminefb: Can't reserve regbase.\n");
    633		ret = -EBUSY;
    634		goto err_free_hw;
    635	}
    636	hw->v_regs = ioremap(carminefb_fix.mmio_start,
    637			carminefb_fix.mmio_len);
    638	if (!hw->v_regs) {
    639		printk(KERN_ERR "carminefb: Can't remap %s register.\n",
    640				carminefb_fix.id);
    641		goto err_free_reg_mmio;
    642	}
    643
    644	carminefb_fix.smem_start = pci_resource_start(dev, CARMINE_MEMORY_BAR);
    645	carminefb_fix.smem_len = pci_resource_len(dev, CARMINE_MEMORY_BAR);
    646
    647	/* The memory area tends to be very large (256 MiB). Remap only what
    648	 * is required for that largest resolution to avoid remaps at run
    649	 * time
    650	 */
    651	if (carminefb_fix.smem_len > CARMINE_TOTAL_DIPLAY_MEM)
    652		carminefb_fix.smem_len = CARMINE_TOTAL_DIPLAY_MEM;
    653
    654	else if (carminefb_fix.smem_len < CARMINE_TOTAL_DIPLAY_MEM) {
    655		printk(KERN_ERR "carminefb: Memory bar is only %d bytes, %d "
    656				"are required.", carminefb_fix.smem_len,
    657				CARMINE_TOTAL_DIPLAY_MEM);
    658		goto err_unmap_vregs;
    659	}
    660
    661	if (!request_mem_region(carminefb_fix.smem_start,
    662				carminefb_fix.smem_len,	"carminefb smem")) {
    663		printk(KERN_ERR "carminefb: Can't reserve smem.\n");
    664		goto err_unmap_vregs;
    665	}
    666
    667	hw->screen_mem = ioremap(carminefb_fix.smem_start,
    668			carminefb_fix.smem_len);
    669	if (!hw->screen_mem) {
    670		printk(KERN_ERR "carmine: Can't ioremap smem area.\n");
    671		goto err_reg_smem;
    672	}
    673
    674	ret = init_hardware(hw);
    675	if (ret)
    676		goto err_unmap_screen;
    677
    678	info = NULL;
    679	if (fb_displays & CARMINE_USE_DISPLAY0) {
    680		ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP0_REG,
    681				hw->screen_mem, CARMINE_DISPLAY_MEM * 0,
    682				device, &info);
    683		if (ret)
    684			goto err_deinit_hw;
    685	}
    686
    687	hw->fb[0] = info;
    688
    689	info = NULL;
    690	if (fb_displays & CARMINE_USE_DISPLAY1) {
    691		ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP1_REG,
    692				hw->screen_mem, CARMINE_DISPLAY_MEM * 1,
    693				device, &info);
    694		if (ret)
    695			goto err_cleanup_fb0;
    696	}
    697
    698	hw->fb[1] = info;
    699	info = NULL;
    700
    701	pci_set_drvdata(dev, hw);
    702	return 0;
    703
    704err_cleanup_fb0:
    705	cleanup_fb_device(hw->fb[0]);
    706err_deinit_hw:
    707	/* disable clock, etc */
    708	c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
    709err_unmap_screen:
    710	iounmap(hw->screen_mem);
    711err_reg_smem:
    712	release_mem_region(carminefb_fix.smem_start, carminefb_fix.smem_len);
    713err_unmap_vregs:
    714	iounmap(hw->v_regs);
    715err_free_reg_mmio:
    716	release_mem_region(carminefb_fix.mmio_start, carminefb_fix.mmio_len);
    717err_free_hw:
    718	kfree(hw);
    719err_enable_pci:
    720	pci_disable_device(dev);
    721	return ret;
    722}
    723
    724static void carminefb_remove(struct pci_dev *dev)
    725{
    726	struct carmine_hw *hw = pci_get_drvdata(dev);
    727	struct fb_fix_screeninfo fix;
    728	int i;
    729
    730	/* in case we use only fb1 and not fb1 */
    731	if (hw->fb[0])
    732		fix = hw->fb[0]->fix;
    733	else
    734		fix = hw->fb[1]->fix;
    735
    736	/* deactivate display(s) and switch clocks */
    737	c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
    738	c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
    739	c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
    740
    741	for (i = 0; i < MAX_DISPLAY; i++)
    742		cleanup_fb_device(hw->fb[i]);
    743
    744	iounmap(hw->screen_mem);
    745	release_mem_region(fix.smem_start, fix.smem_len);
    746	iounmap(hw->v_regs);
    747	release_mem_region(fix.mmio_start, fix.mmio_len);
    748
    749	pci_disable_device(dev);
    750	kfree(hw);
    751}
    752
    753#define PCI_VENDOR_ID_FUJITU_LIMITED 0x10cf
    754static struct pci_device_id carmine_devices[] = {
    755{
    756	PCI_DEVICE(PCI_VENDOR_ID_FUJITU_LIMITED, 0x202b)},
    757	{0, 0, 0, 0, 0, 0, 0}
    758};
    759
    760MODULE_DEVICE_TABLE(pci, carmine_devices);
    761
    762static struct pci_driver carmine_pci_driver = {
    763	.name		= "carminefb",
    764	.id_table	= carmine_devices,
    765	.probe		= carminefb_probe,
    766	.remove		= carminefb_remove,
    767};
    768
    769static int __init carminefb_init(void)
    770{
    771	if (!(fb_displays &
    772		(CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1))) {
    773		printk(KERN_ERR "If you disable both displays than you don't "
    774				"need the driver at all\n");
    775		return -EINVAL;
    776	}
    777	return pci_register_driver(&carmine_pci_driver);
    778}
    779module_init(carminefb_init);
    780
    781static void __exit carminefb_cleanup(void)
    782{
    783	pci_unregister_driver(&carmine_pci_driver);
    784}
    785module_exit(carminefb_cleanup);
    786
    787MODULE_AUTHOR("Sebastian Siewior <bigeasy@linutronix.de>");
    788MODULE_DESCRIPTION("Framebuffer driver for Fujitsu Carmine based devices");
    789MODULE_LICENSE("GPL v2");