Skip to content

Commit

Permalink
[PATCH] fbdev: framebuffer driver for Geode GX
Browse files Browse the repository at this point in the history
A framebuffer driver for the display controller in AMD Geode GX processors
(Geode GX533, Geode GX500 etc.).  Tested at 640x480, 800x600, 1024x768 and
1280x1024 at 8, 16, and 24 bpp with both CRT and TFT.  No accelerated features
currently implemented and compression remains disabled.

This driver requires that the BIOS (or the SoftVG/Firmbase code in the BIOS)
has created an appropriate virtual PCI header.

Signed-off-by: David Vrabel <dvrabel@arcom.com>
Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
David Vrabel authored and Linus Torvalds committed Mar 27, 2006
1 parent 7a07cd7 commit fc4effc
Show file tree
Hide file tree
Showing 7 changed files with 1,003 additions and 2 deletions.
17 changes: 16 additions & 1 deletion drivers/video/geode/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,24 @@ config FB_GEODE
Say 'Y' here to allow you to select framebuffer drivers for
the AMD Geode family of processors.

config FB_GEODE_GX
tristate "AMD Geode GX framebuffer support (EXPERIMENTAL)"
depends on FB && FB_GEODE && EXPERIMENTAL
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
Framebuffer driver for the display controller integrated into the
AMD Geode GX processors.

To compile this driver as a module, choose M here: the module will be
called gxfb.

If unsure, say N.

config FB_GEODE_GX1
tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
depends on FB_GEODE && EXPERIMENTAL
depends on FB && FB_GEODE && EXPERIMENTAL
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
Expand Down
4 changes: 3 additions & 1 deletion drivers/video/geode/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Makefile for the Geode family framebuffer drivers

obj-$(CONFIG_FB_GEODE_GX1) += gx1fb.o
obj-$(CONFIG_FB_GEODE_GX) += gxfb.o

gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o
gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o
gxfb-objs := gxfb_core.o display_gx.o video_gx.o
156 changes: 156 additions & 0 deletions drivers/video/geode/display_gx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* Geode GX display controller.
*
* Copyright (C) 2005 Arcom Control Systems Ltd.
*
* Portions from AMD's original 2.4 driver:
* Copyright (C) 2004 Advanced Micro Devices, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by * the
* Free Software Foundation; either version 2 of the License, or * (at your
* option) any later version.
*/
#include <linux/spinlock.h>
#include <linux/fb.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/div64.h>
#include <asm/delay.h>

#include "geodefb.h"
#include "display_gx.h"

int gx_frame_buffer_size(void)
{
/* Assuming 16 MiB. */
return 16*1024*1024;
}

int gx_line_delta(int xres, int bpp)
{
/* Must be a multiple of 8 bytes. */
return (xres * (bpp >> 3) + 7) & ~0x7;
}

static void gx_set_mode(struct fb_info *info)
{
struct geodefb_par *par = info->par;
u32 gcfg, dcfg;
int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;

/* Unlock the display controller registers. */
readl(par->dc_regs + DC_UNLOCK);
writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);

gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
dcfg = readl(par->dc_regs + DC_DISPLAY_CFG);

/* Disable the timing generator. */
dcfg &= ~(DC_DCFG_TGEN);
writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);

/* Wait for pending memory requests before disabling the FIFO load. */
udelay(100);

/* Disable FIFO load and compression. */
gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
writel(gcfg, par->dc_regs + DC_GENERAL_CFG);

/* Setup DCLK and its divisor. */
par->vid_ops->set_dclk(info);

/*
* Setup new mode.
*/

/* Clear all unused feature bits. */
gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE;
dcfg = 0;

/* Set FIFO priority (default 6/5) and enable. */
/* FIXME: increase fifo priority for 1280x1024 and higher modes? */
gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE;

/* Framebuffer start offset. */
writel(0, par->dc_regs + DC_FB_ST_OFFSET);

/* Line delta and line buffer length. */
writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH);
writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
par->dc_regs + DC_LINE_SIZE);

/* Enable graphics and video data and unmask address lines. */
dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M;

/* Set pixel format. */
switch (info->var.bits_per_pixel) {
case 8:
dcfg |= DC_DCFG_DISP_MODE_8BPP;
break;
case 16:
dcfg |= DC_DCFG_DISP_MODE_16BPP;
dcfg |= DC_DCFG_16BPP_MODE_565;
break;
case 32:
dcfg |= DC_DCFG_DISP_MODE_24BPP;
dcfg |= DC_DCFG_PALB;
break;
}

/* Enable timing generator. */
dcfg |= DC_DCFG_TGEN;

/* Horizontal and vertical timings. */
hactive = info->var.xres;
hblankstart = hactive;
hsyncstart = hblankstart + info->var.right_margin;
hsyncend = hsyncstart + info->var.hsync_len;
hblankend = hsyncend + info->var.left_margin;
htotal = hblankend;

vactive = info->var.yres;
vblankstart = vactive;
vsyncstart = vblankstart + info->var.lower_margin;
vsyncend = vsyncstart + info->var.vsync_len;
vblankend = vsyncend + info->var.upper_margin;
vtotal = vblankend;

writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING);
writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING);
writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING);

writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING);
writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING);
writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING);

/* Write final register values. */
writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
writel(gcfg, par->dc_regs + DC_GENERAL_CFG);

par->vid_ops->configure_display(info);

/* Relock display controller registers */
writel(0, par->dc_regs + DC_UNLOCK);
}

static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno,
unsigned red, unsigned green, unsigned blue)
{
struct geodefb_par *par = info->par;
int val;

/* Hardware palette is in RGB 8-8-8 format. */
val = (red << 8) & 0xff0000;
val |= (green) & 0x00ff00;
val |= (blue >> 8) & 0x0000ff;

writel(regno, par->dc_regs + DC_PAL_ADDRESS);
writel(val, par->dc_regs + DC_PAL_DATA);
}

struct geode_dc_ops gx_dc_ops = {
.set_mode = gx_set_mode,
.set_palette_reg = gx_set_hw_palette_reg,
};
96 changes: 96 additions & 0 deletions drivers/video/geode/display_gx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Geode GX display controller
*
* Copyright (C) 2006 Arcom Control Systems Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __DISPLAY_GX_H__
#define __DISPLAY_GX_H__

int gx_frame_buffer_size(void);
int gx_line_delta(int xres, int bpp);

extern struct geode_dc_ops gx_dc_ops;

/* Display controller registers */

#define DC_UNLOCK 0x00
# define DC_UNLOCK_CODE 0x00004758

#define DC_GENERAL_CFG 0x04
# define DC_GCFG_DFLE 0x00000001
# define DC_GCFG_CURE 0x00000002
# define DC_GCFG_ICNE 0x00000004
# define DC_GCFG_VIDE 0x00000008
# define DC_GCFG_CMPE 0x00000020
# define DC_GCFG_DECE 0x00000040
# define DC_GCFG_VGAE 0x00000080
# define DC_GCFG_DFHPSL_MASK 0x00000F00
# define DC_GCFG_DFHPSL_POS 8
# define DC_GCFG_DFHPEL_MASK 0x0000F000
# define DC_GCFG_DFHPEL_POS 12
# define DC_GCFG_STFM 0x00010000
# define DC_GCFG_FDTY 0x00020000
# define DC_GCFG_VGAFT 0x00040000
# define DC_GCFG_VDSE 0x00080000
# define DC_GCFG_YUVM 0x00100000
# define DC_GCFG_VFSL 0x00800000
# define DC_GCFG_SIGE 0x01000000
# define DC_GCFG_SGRE 0x02000000
# define DC_GCFG_SGFR 0x04000000
# define DC_GCFG_CRC_MODE 0x08000000
# define DC_GCFG_DIAG 0x10000000
# define DC_GCFG_CFRW 0x20000000

#define DC_DISPLAY_CFG 0x08
# define DC_DCFG_TGEN 0x00000001
# define DC_DCFG_GDEN 0x00000008
# define DC_DCFG_VDEN 0x00000010
# define DC_DCFG_TRUP 0x00000040
# define DC_DCFG_DISP_MODE_MASK 0x00000300
# define DC_DCFG_DISP_MODE_8BPP 0x00000000
# define DC_DCFG_DISP_MODE_16BPP 0x00000100
# define DC_DCFG_DISP_MODE_24BPP 0x00000200
# define DC_DCFG_16BPP_MODE_MASK 0x00000c00
# define DC_DCFG_16BPP_MODE_565 0x00000000
# define DC_DCFG_16BPP_MODE_555 0x00000100
# define DC_DCFG_16BPP_MODE_444 0x00000200
# define DC_DCFG_DCEN 0x00080000
# define DC_DCFG_PALB 0x02000000
# define DC_DCFG_FRLK 0x04000000
# define DC_DCFG_VISL 0x08000000
# define DC_DCFG_FRSL 0x20000000
# define DC_DCFG_A18M 0x40000000
# define DC_DCFG_A20M 0x80000000

#define DC_FB_ST_OFFSET 0x10

#define DC_LINE_SIZE 0x30
# define DC_LINE_SIZE_FB_LINE_SIZE_MASK 0x000007ff
# define DC_LINE_SIZE_FB_LINE_SIZE_POS 0
# define DC_LINE_SIZE_CB_LINE_SIZE_MASK 0x007f0000
# define DC_LINE_SIZE_CB_LINE_SIZE_POS 16
# define DC_LINE_SIZE_VID_LINE_SIZE_MASK 0xff000000
# define DC_LINE_SIZE_VID_LINE_SIZE_POS 24

#define DC_GFX_PITCH 0x34
# define DC_GFX_PITCH_FB_PITCH_MASK 0x0000ffff
# define DC_GFX_PITCH_FB_PITCH_POS 0
# define DC_GFX_PITCH_CB_PITCH_MASK 0xffff0000
# define DC_GFX_PITCH_CB_PITCH_POS 16

#define DC_H_ACTIVE_TIMING 0x40
#define DC_H_BLANK_TIMING 0x44
#define DC_H_SYNC_TIMING 0x48
#define DC_V_ACTIVE_TIMING 0x50
#define DC_V_BLANK_TIMING 0x54
#define DC_V_SYNC_TIMING 0x58

#define DC_PAL_ADDRESS 0x70
#define DC_PAL_DATA 0x74

#endif /* !__DISPLAY_GX1_H__ */
Loading

0 comments on commit fc4effc

Please sign in to comment.