patch-2.4.22 linux-2.4.22/drivers/video/radeonfb.c
Next file: linux-2.4.22/drivers/video/sis/300vtbl.h
Previous file: linux-2.4.22/drivers/video/radeon.h
Back to the patch index
Back to the overall index
- Lines: 4563
- Date:
2003-08-25 04:44:42.000000000 -0700
- Orig file:
linux-2.4.21/drivers/video/radeonfb.c
- Orig date:
2003-06-13 07:51:37.000000000 -0700
diff -urN linux-2.4.21/drivers/video/radeonfb.c linux-2.4.22/drivers/video/radeonfb.c
@@ -2,7 +2,7 @@
* drivers/video/radeonfb.c
* framebuffer driver for ATI Radeon chipset video boards
*
- * Copyright 2000 Ani Joshi <ajoshi@unixbox.com>
+ * Copyright 2000 Ani Joshi <ajoshi@kernel.crashing.org>
*
*
* ChangeLog:
@@ -19,13 +19,94 @@
* 2001-11-18 DFP fixes, Kevin Hendricks, 0.1.3
* 2001-11-29 more cmap, backlight fixes, Benjamin Herrenschmidt
* 2002-01-18 DFP panel detection via BIOS, Michael Clark, 0.1.4
+ * 2002-06-02 console switching, mode set fixes, accel fixes
+ * 2002-06-03 MTRR support, Peter Horton, 0.1.5
+ * 2002-09-21 rv250, r300, m9 initial support,
+ * added mirror option, 0.1.6
+ * 2003-04-10 accel engine fixes, 0.1.7
+ * 2003-04-12 Mac PowerBook sleep fixes, Benjamin Herrenschmidt,
+ * 0.1.8
*
- * Special thanks to ATI DevRel team for their hardware donations.
+ * Other change (--BenH)
+ *
+ * 2003-01-01 - Tweaks for PLL on some iBooks
+ * - Fix SURFACE_CNTL usage on r9000
+ * 2003-03-23 - Added new Power Management code from ATI
+ * - Added default PLL values for r300 from lkml
+ * - Fix mirror ioctl result code (that ioctl still need some
+ * rework to actually use the second head)
+ * 2003-03-26 - Never set TMDS_PLL_EN, it seem to break more than
+ * just old r300's
+ * 2003-04-02 - Got final word from ATI, TMDS_PLL_EN has to be flipped
+ * depending if we are dealing with an "RV" card or not
+ * - Comsetic changes to sleep code, make it a bit more robust
+ * hopefully
+ * - Fix 800x600-8 mode accel (Daniel Mantione)
+ * - Fix scaling on LCDs (not yet preserving aspect ratio though)
+ * - Properly set scroll mode to SCROLL_YREDRAW when accel
+ * is disabled from fbset
+ * - Add some more radeon PCI IDs & default PLL values
+ * 2003-04-05 - Update the code that retreive the panel infos from the
+ * BIOS to match what XFree is doing
+ * - Avoid a divide by 0 when failing to retreive those infos
+ * 2003-04-07 - Fix the M6 video RAM workaround
+ * - Some bits in the PM code were flipped, fix that.
+ * - RB2D_DSTCACHE_MODE shouldn't be cleared on r300 (and
+ * maybe not on others according to a comment in XFree, but
+ * we keep working code for now).
+ * - Use ROP3_S for rectangle fill
+ * 2003-04-10 - Re-change the pitch workaround. We now align the pitch
+ * when accel is enabled for a given mode, and we don't when
+ * accel is disabled. That should properly deal with all cases
+ * and allows us to remove the "special case" accel code
+ * - Bring in XFree workaround to not write the same value to
+ * the PLL (can cause blanking of some panels)
+ * - Bring in some of Peter Horton fixes (accel reset, cleanups)
+ * still some more to get in though...
+ * - Back to use of ROP3_P for rectangle fill (hrm...)
+ * 2003-04-11 - Properly reset accel engine on each console switch so
+ * we work around switching from XFree leaving it in a weird
+ * state. Also extend the comparison of values causing us to
+ * reload the mode on console switch.
+ * 2003-04-30 - For BIOS returned LCD infos, assume high sync polarity
+ * 2003-07-08 - Fix an oops during boot related to disp not beeing initialized
+ * when modedb called us back for set_var. Remove bogus refs to
+ * RADEON_PM chip, this is really a mach64 chip, not a Radeon.
+ * Add some DFP blanking support
+ * 2003-07-11 - Merged with Ani's 0.1.8 version
+ *
+ * Special thanks to ATI DevRel team for their hardware donations,
+ * and for spending the time to fix the power management code !
+ *
+ * Note: This driver in in bad need of beeing completely re-organized.
+ * My long term plans, if I ever get enough time for that, is
+ * to split the actual mode setting code so it can properly
+ * work on any head, the probe code, which will be stuffed with
+ * OF parsing on PPC and i2c fallback (look at what XFree does)
+ * and the PM code ought to be in a separate file. --BenH.
*
+ *
+ * Known Bugs:
+ *
+ * - Incompatible with ATI FireGL drivers. They are playing with things
+ * like MC_FB_LOCATION behind our back. Not much we can do. This is
+ * becoming a real problem as DRI is also playing with those and the
+ * GATOS CVS as well in a different way.
+ * We should really define _once for all_ the way we want those setup
+ * and do it the same way everywhere or we won't be able to keep
+ * compatibility with radeonfb.
+ * IMHO, the proper setup is what radeon_fixup_apertures() does on
+ * PPC when SET_MC_FB_FROM_APERTURE is defined (not the case currently
+ * because of compatiblity problems with DRI). This is, I think, also
+ * what GATOS does. We shall ask ATI what they do in the FireGL drivers
+ * - We don't preserve aspect ratio on scaled modes on LCDs yet
+ * - The way we retreive the BIOS informations probably doesn't work with
+ * anything but the primary card since we need a "live" BIOS image in
+ * memory to find the tables configured by the BIOS during POST stage.
*/
-#define RADEON_VERSION "0.1.4"
+#define RADEON_VERSION "0.1.8-ben"
#include <linux/config.h>
@@ -39,6 +120,7 @@
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/console.h>
+#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/ioport.h>
#include <linux/init.h>
@@ -46,7 +128,8 @@
#include <linux/vmalloc.h>
#include <asm/io.h>
-#if defined(__powerpc__)
+#include <asm/uaccess.h>
+#ifdef CONFIG_ALL_PPC
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <video/macmodes.h>
@@ -68,7 +151,11 @@
#include <linux/pmu.h>
#endif
-#endif /* __powerpc__ */
+#endif /* CONFIG_ALL_PPC */
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
@@ -78,6 +165,8 @@
#include "radeon.h"
+#include <linux/radeonfb.h>
+
#define DEBUG 0
@@ -90,18 +179,103 @@
enum radeon_chips {
- RADEON_QD, /* Radeon R100 */
- RADEON_QE, /* Radeon R100 */
- RADEON_QF, /* Radeon R100 */
- RADEON_QG, /* Radeon R100 */
- RADEON_QY, /* Radeon RV100 (VE) */
- RADEON_QZ, /* Radeon RV100 (VE) */
- RADEON_QL, /* Radeon R200 (8500) */
- RADEON_QW, /* Radeon RV200 (7500) */
- RADEON_LW, /* Radeon Mobility M7 */
- RADEON_LY, /* Radeon Mobility M6 */
- RADEON_LZ, /* Radeon Mobility M6 */
- RADEON_PM /* Radeon Mobility P/M */
+ RADEON_QD,
+ RADEON_QE,
+ RADEON_QF,
+ RADEON_QG,
+ RADEON_QY,
+ RADEON_QZ,
+ RADEON_LW,
+ RADEON_LX,
+ RADEON_LY,
+ RADEON_LZ,
+ RADEON_QL,
+ RADEON_QN,
+ RADEON_QO,
+ RADEON_Ql,
+ RADEON_BB,
+ RADEON_QM,
+ RADEON_QW,
+ RADEON_QX,
+ RADEON_Id,
+ RADEON_Ie,
+ RADEON_If,
+ RADEON_Ig,
+ RADEON_Y_,
+ RADEON_Ld,
+ RADEON_Le,
+ RADEON_Lf,
+ RADEON_Lg,
+ RADEON_ND,
+ RADEON_NE,
+ RADEON_NF,
+ RADEON_NG,
+ RADEON_AE,
+ RADEON_AF,
+ RADEON_AD,
+ RADEON_NH,
+ RADEON_NI,
+ RADEON_AP,
+ RADEON_AR,
+};
+
+enum radeon_arch {
+ RADEON_R100,
+ RADEON_M6,
+ RADEON_RV100,
+ RADEON_R200,
+ RADEON_M7,
+ RADEON_RV200,
+ RADEON_M9,
+ RADEON_RV250,
+ RADEON_RV280,
+ RADEON_R300,
+ RADEON_R350,
+ RADEON_RV350,
+};
+
+static struct radeon_chip_info {
+ const char *name;
+ unsigned char arch;
+} radeon_chip_info[] __devinitdata = {
+ { "QD", RADEON_R100 },
+ { "QE", RADEON_R100 },
+ { "QF", RADEON_R100 },
+ { "QG", RADEON_R100 },
+ { "VE QY", RADEON_RV100 },
+ { "VE QZ", RADEON_RV100 },
+ { "M7 LW", RADEON_M7 },
+ { "M7 LX", RADEON_M7 },
+ { "M6 LY", RADEON_M6 },
+ { "M6 LZ", RADEON_M6 },
+ { "8500 QL", RADEON_R200 },
+ { "8500 QN", RADEON_R200 },
+ { "8500 QO", RADEON_R200 },
+ { "8500 Ql", RADEON_R200 },
+ { "8500 BB", RADEON_R200 },
+ { "9100 QM", RADEON_R200 },
+ { "7500 QW", RADEON_RV200 },
+ { "7500 QX", RADEON_RV200 },
+ { "9000 Id", RADEON_RV250 },
+ { "9000 Ie", RADEON_RV250 },
+ { "9000 If", RADEON_RV250 },
+ { "9000 Ig", RADEON_RV250 },
+ { "9200 Y", RADEON_RV280 },
+ { "M9 Ld", RADEON_M9 },
+ { "M9 Le", RADEON_M9 },
+ { "M9 Lf", RADEON_M9 },
+ { "M9 Lg", RADEON_M9 },
+ { "9700 ND", RADEON_R300 },
+ { "9700 NE", RADEON_R300 },
+ { "9700 NF", RADEON_R350 },
+ { "9700 NG", RADEON_R350 },
+ { "9700 AE", RADEON_R300 },
+ { "9700 AF", RADEON_R300 },
+ { "9500 AD", RADEON_R300 },
+ { "9800 NH", RADEON_R350 },
+ { "9800 NI", RADEON_R350 },
+ { "9600 AP", RADEON_RV350 },
+ { "9600 AR", RADEON_RV350 },
};
@@ -117,18 +291,44 @@
static struct pci_device_id radeonfb_pci_table[] __devinitdata = {
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QD},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QE},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QF},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QG},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QY},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QZ},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QL},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QW},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_LW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LW},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_LY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LY},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_LZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LZ},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_PM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_PM},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QD},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QE},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QF},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QG},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QY},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QZ},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LW},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LX},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LY},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LZ},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QL},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QN, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QN},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QO},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ql, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ql},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_BB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_BB},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QM},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QW},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QX},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Id},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ie, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ie},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_If, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_If},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ig, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ig},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ld, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ld},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Le, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Le},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Lf, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Lf},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Lg, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Lg},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_ND, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_ND},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NE},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NF},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NG},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AE},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AF},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NH, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NH},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NI},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Y_, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Y_},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AD},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AP},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AR},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, radeonfb_pci_table);
@@ -155,7 +355,19 @@
{ CAP0_TRIG_CNTL, 0 },
};
+reg_val common_regs_m6[] = {
+ { OVR_CLR, 0 },
+ { OVR_WID_LEFT_RIGHT, 0 },
+ { OVR_WID_TOP_BOTTOM, 0 },
+ { OV0_SCALE_CNTL, 0 },
+ { SUBPIC_CNTL, 0 },
+ { GEN_INT_CNTL, 0 },
+ { CAP0_TRIG_CNTL, 0 }
+};
+
+
#define COMMON_REGS_SIZE = (sizeof(common_regs)/sizeof(common_regs[0]))
+#define COMMON_REGS_M6_SIZE = (sizeof(common_regs)/sizeof(common_regs_m6[0]))
typedef struct {
u8 clock_chip_type;
@@ -214,6 +426,7 @@
u32 crtc_pitch;
u32 crtc_gen_cntl;
u32 crtc_ext_cntl;
+ u32 crtc_more_cntl;
u32 dac_cntl;
u32 flags;
@@ -242,9 +455,11 @@
u32 tmds_crc;
u32 tmds_transmitter_cntl;
-#if defined(__BIG_ENDIAN)
+ /* Dynamic clock control */
+ u32 vclk_ecp_cntl;
+
+ /* Endian control */
u32 surface_cntl;
-#endif
};
@@ -254,15 +469,17 @@
struct radeon_regs state;
struct radeon_regs init_state;
- char name[17];
+ char name[16];
char ram_type[12];
- u32 mmio_base_phys;
- u32 fb_base_phys;
+ unsigned long mmio_base_phys;
+ unsigned long fb_base_phys;
unsigned long mmio_base;
unsigned long fb_base;
+ unsigned long fb_local_base;
+
struct pci_dev *pdev;
unsigned char *EDID;
@@ -274,11 +491,13 @@
struct { u8 red, green, blue, pad; } palette[256];
- int chipset;
+ short chipset;
+ unsigned char arch;
int video_ram;
u8 rev;
int pitch, bpp, depth;
int xres, yres, pixclock;
+ int xres_virtual, yres_virtual;
int use_default_var;
int got_dfpinfo;
@@ -301,8 +520,7 @@
struct ram_info ram;
- u32 hack_crtc_ext_cntl;
- u32 hack_crtc_v_sync_strt_wid;
+ int mtrr_hdl;
#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
union {
@@ -319,10 +537,13 @@
#endif
#ifdef CONFIG_PMAC_PBOOK
- unsigned char *save_framebuffer;
int pm_reg;
+ u32 save_regs[64];
+ u32 mdll, mdll2;
#endif
+ int asleep;
+
struct radeonfb_info *next;
};
@@ -344,8 +565,12 @@
#define INREG(addr) readl((rinfo->mmio_base)+addr)
#define OUTREG(addr,val) writel(val, (rinfo->mmio_base)+addr)
-#define OUTPLL(addr,val) OUTREG8(CLOCK_CNTL_INDEX, (addr & 0x0000001f) | 0x00000080); \
- OUTREG(CLOCK_CNTL_DATA, val)
+#define OUTPLL(addr,val) \
+ do { \
+ OUTREG8(CLOCK_CNTL_INDEX, (addr & 0x0000003f) | 0x00000080); \
+ OUTREG(CLOCK_CNTL_DATA, val); \
+ } while (0) \
+
#define OUTPLLP(addr,val,mask) \
do { \
unsigned int _tmp = INPLL(addr); \
@@ -363,9 +588,9 @@
} while (0)
-static __inline__ u32 _INPLL(struct radeonfb_info *rinfo, unsigned long addr)
+static __inline__ u32 _INPLL(struct radeonfb_info *rinfo, u32 addr)
{
- OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000001f);
+ OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
return (INREG(CLOCK_CNTL_DATA));
}
@@ -487,9 +712,36 @@
static void _radeon_engine_reset(struct radeonfb_info *rinfo)
{
u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
+ u32 host_path_cntl;
radeon_engine_flush (rinfo);
+ /* Some ASICs have bugs with dynamic-on feature, which are
+ * ASIC-version dependent, so we force all blocks on for now
+ * -- from XFree86
+ * We don't do that on macs, things just work here with dynamic
+ * clocking... --BenH
+ */
+#ifdef CONFIG_ALL_PPC
+ if (_machine != _MACH_Pmac && rinfo->hasCRTC2)
+#else
+ if (rinfo->hasCRTC2)
+#endif
+ {
+ u32 tmp;
+
+ tmp = INPLL(SCLK_CNTL);
+ OUTPLL(SCLK_CNTL, ((tmp & ~DYN_STOP_LAT_MASK) |
+ CP_MAX_DYN_STOP_LAT |
+ SCLK_FORCEON_MASK));
+
+ if (rinfo->arch == RADEON_RV200)
+ {
+ tmp = INPLL(SCLK_MORE_CNTL);
+ OUTPLL(SCLK_MORE_CNTL, tmp | SCLK_MORE_FORCEON);
+ }
+ }
+
clock_cntl_index = INREG(CLOCK_CNTL_INDEX);
mclk_cntl = INPLL(MCLK_CNTL);
@@ -500,32 +752,51 @@
FORCEON_YCLKB |
FORCEON_MC |
FORCEON_AIC));
+
+ host_path_cntl = INREG(HOST_PATH_CNTL);
rbbm_soft_reset = INREG(RBBM_SOFT_RESET);
- OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset |
- SOFT_RESET_CP |
- SOFT_RESET_HI |
- SOFT_RESET_SE |
- SOFT_RESET_RE |
- SOFT_RESET_PP |
- SOFT_RESET_E2 |
- SOFT_RESET_RB |
- SOFT_RESET_HDP);
- INREG(RBBM_SOFT_RESET);
- OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32)
- ~(SOFT_RESET_CP |
- SOFT_RESET_HI |
- SOFT_RESET_SE |
- SOFT_RESET_RE |
- SOFT_RESET_PP |
- SOFT_RESET_E2 |
- SOFT_RESET_RB |
- SOFT_RESET_HDP));
- INREG(RBBM_SOFT_RESET);
+ if (rinfo->arch == RADEON_R300) {
+ u32 tmp;
+
+ OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset |
+ SOFT_RESET_CP |
+ SOFT_RESET_HI |
+ SOFT_RESET_E2));
+ INREG(RBBM_SOFT_RESET);
+ OUTREG(RBBM_SOFT_RESET, 0);
+ tmp = INREG(RB2D_DSTCACHE_MODE);
+ OUTREG(RB2D_DSTCACHE_MODE, tmp | (1 << 17)); /* FIXME */
+ } else {
+ OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset |
+ SOFT_RESET_CP |
+ SOFT_RESET_HI |
+ SOFT_RESET_SE |
+ SOFT_RESET_RE |
+ SOFT_RESET_PP |
+ SOFT_RESET_E2 |
+ SOFT_RESET_RB);
+ INREG(RBBM_SOFT_RESET);
+ OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32)
+ ~(SOFT_RESET_CP |
+ SOFT_RESET_HI |
+ SOFT_RESET_SE |
+ SOFT_RESET_RE |
+ SOFT_RESET_PP |
+ SOFT_RESET_E2 |
+ SOFT_RESET_RB));
+ INREG(RBBM_SOFT_RESET);
+ }
+
+ OUTREG(HOST_PATH_CNTL, host_path_cntl | HDP_SOFT_RESET);
+ INREG(HOST_PATH_CNTL);
+ OUTREG(HOST_PATH_CNTL, host_path_cntl);
+
+ if (rinfo->arch != RADEON_R300)
+ OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset);
- OUTPLL(MCLK_CNTL, mclk_cntl);
OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index);
- OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset);
+ OUTPLL(MCLK_CNTL, mclk_cntl);
return;
}
@@ -533,37 +804,11 @@
#define radeon_engine_reset() _radeon_engine_reset(rinfo)
-static __inline__ u8 radeon_get_post_div_bitval(int post_div)
-{
- switch (post_div) {
- case 1:
- return 0x00;
- case 2:
- return 0x01;
- case 3:
- return 0x04;
- case 4:
- return 0x02;
- case 6:
- return 0x06;
- case 8:
- return 0x03;
- case 12:
- return 0x07;
- default:
- return 0x02;
- }
-}
-
-
-
static __inline__ int round_div(int num, int den)
{
return (num + (den / 2)) / den;
}
-
-
static __inline__ int min_bits_req(int val)
{
int bits_req = 0;
@@ -579,7 +824,6 @@
return (bits_req);
}
-
static __inline__ int _max(int val1, int val2)
{
if (val1 >= val2)
@@ -596,15 +840,27 @@
static char fontname[40] __initdata;
static char *mode_option __initdata;
-static char noaccel __initdata = 0;
+static char noaccel = 0;
+static char mirror = 0;
static int panel_yres __initdata = 0;
static char force_dfp __initdata = 0;
+static char force_crt __initdata = 0;
+static char force_nolcd __initdata = 0;
static struct radeonfb_info *board_list = NULL;
+static char nomtrr __initdata = 0;
#ifdef FBCON_HAS_CFB8
static struct display_switch fbcon_radeon8;
#endif
+#ifdef FBCON_HAS_CFB16
+static struct display_switch fbcon_radeon16;
+#endif
+
+#ifdef FBCON_HAS_CFB32
+static struct display_switch fbcon_radeon32;
+#endif
+
/*
* prototypes
@@ -636,46 +892,41 @@
static void radeon_set_dispsw (struct radeonfb_info *rinfo, struct display *disp);
static void radeon_save_state (struct radeonfb_info *rinfo,
struct radeon_regs *save);
-static void radeon_engine_init (struct radeonfb_info *rinfo);
+static int radeon_engine_init (struct radeonfb_info *rinfo);
static void radeon_load_video_mode (struct radeonfb_info *rinfo,
struct fb_var_screeninfo *mode);
static void radeon_write_mode (struct radeonfb_info *rinfo,
struct radeon_regs *mode);
static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo);
static int __devinit radeon_init_disp (struct radeonfb_info *rinfo);
-static int radeon_init_disp_var (struct radeonfb_info *rinfo);
static int radeonfb_pci_register (struct pci_dev *pdev,
const struct pci_device_id *ent);
static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev);
-static char *radeon_find_rom(struct radeonfb_info *rinfo);
-static void radeon_get_pllinfo(struct radeonfb_info *rinfo, char *bios_seg);
-static void radeon_get_moninfo (struct radeonfb_info *rinfo);
-static int radeon_get_dfpinfo (struct radeonfb_info *rinfo);
-static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo);
-static void radeon_get_EDID(struct radeonfb_info *rinfo);
-static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo);
-static void radeon_update_default_var(struct radeonfb_info *rinfo);
-
-
-#ifdef CONFIG_ALL_PPC
-static int radeon_read_OF (struct radeonfb_info *rinfo);
-static int radeon_get_EDID_OF(struct radeonfb_info *rinfo);
-extern struct device_node *pci_device_to_OF_node(struct pci_dev *dev);
+static int radeon_do_set_var (struct fb_var_screeninfo *var, int con,
+ int real, struct fb_info *info);
#ifdef CONFIG_PMAC_PBOOK
-int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when);
static struct pmu_sleep_notifier radeon_sleep_notifier = {
radeon_sleep_notify, SLEEP_LEVEL_VIDEO,
};
+#endif /* CONFIG_PMAC_PBOOK */
+#ifdef CONFIG_PMAC_BACKLIGHT
static int radeon_set_backlight_enable(int on, int level, void *data);
static int radeon_set_backlight_level(int level, void *data);
static struct backlight_controller radeon_backlight_controller = {
radeon_set_backlight_enable,
radeon_set_backlight_level
};
-#endif /* CONFIG_PMAC_PBOOK */
-
-#endif /* CONFIG_ALL_PPC */
+static void OUTMC( struct radeonfb_info *rinfo, u8 indx, u32 value);
+static u32 INMC(struct radeonfb_info *rinfo, u8 indx);
+static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo);
+static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo);
+static void radeon_pm_yclk_mclk_sync(struct radeonfb_info *rinfo);
+static void radeon_pm_program_mode_reg(struct radeonfb_info *rinfo, u16 value, u8 delay_required);
+static void radeon_pm_enable_dll(struct radeonfb_info *rinfo);
+static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo);
+#endif /* CONFIG_PMAC_BACKLIGHT */
static struct fb_ops radeon_fb_ops = {
fb_get_fix: radeonfb_get_fix,
@@ -729,10 +980,20 @@
memcpy(fontname, this_opt + 5, i);
} else if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
+ } else if (!strncmp(this_opt, "mirror", 6)) {
+ mirror = 1;
} else if (!strncmp(this_opt, "dfp", 3)) {
force_dfp = 1;
+ force_nolcd = 1;
+ } else if (!strncmp(this_opt, "crt", 3)) {
+ force_crt = 1;
+ force_nolcd = 1;
+ } else if (!strncmp(this_opt, "nolcd", 5)) {
+ force_nolcd = 1;
} else if (!strncmp(this_opt, "panel_yres:", 11)) {
panel_yres = simple_strtoul((this_opt+11), NULL, 0);
+ } else if (!strncmp(this_opt, "nomtrr", 6)) {
+ nomtrr = 1;
} else
mode_option = this_opt;
}
@@ -750,500 +1011,185 @@
MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset");
MODULE_LICENSE("GPL");
-static int radeonfb_pci_register (struct pci_dev *pdev,
- const struct pci_device_id *ent)
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel, "Disable (1) or enable (0) the usage of the 2d accel engine");
+MODULE_PARM(force_dfp, "i");
+MODULE_PARM_DESC(force_dfp,"Force (1) the usage of a digital flat panel");
+MODULE_PARM(force_crt, "i");
+MODULE_PARM_DESC(force_crt,"Force (1) the usage of a CRT monitor");
+MODULE_PARM(force_nolcd, "i");
+MODULE_PARM_DESC(force_nolcd,"Avoid (1) the usage of a digital flat panel");
+
+static unsigned char *radeon_find_rom(struct radeonfb_info *rinfo)
+{
+#if defined(__i386__)
+ /* I simplified this code as we used to miss the signatures in
+ * a lot of case. It's now closer to XFree, we just don't check
+ * for signatures at all... Something better will have to be done
+ * later obviously
+ */
+ u32 segstart;
+ unsigned char *rom_base;
+
+ for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
+ rom_base = (char *)ioremap(segstart, 0x1000);
+ if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
+ return rom_base;
+ iounmap(rom_base);
+ }
+#endif
+ return NULL;
+}
+
+#ifdef CONFIG_ALL_PPC
+static int radeon_read_OF (struct radeonfb_info *rinfo)
{
- struct radeonfb_info *rinfo;
- u32 tmp;
- int i, j;
+ struct device_node *dp;
+ unsigned int *xtal;
- RTRACE("radeonfb_pci_register BEGIN\n");
+ dp = pci_device_to_OF_node(rinfo->pdev);
+ if (dp == NULL)
+ return 0;
- rinfo = kmalloc (sizeof (struct radeonfb_info), GFP_KERNEL);
- if (!rinfo) {
- printk ("radeonfb: could not allocate memory\n");
- return -ENODEV;
- }
+ xtal = (unsigned int *) get_property(dp, "ATY,RefCLK", 0);
+ if ((xtal == NULL) || (*xtal == 0))
+ return 0;
- memset (rinfo, 0, sizeof (struct radeonfb_info));
+ rinfo->pll.ref_clk = *xtal / 10;
- rinfo->pdev = pdev;
+ return 1;
+}
+#endif
- /* enable device */
- {
- int err;
+static void radeon_get_pllinfo(struct radeonfb_info *rinfo, char *bios_seg)
+{
+ void *bios_header;
+ void *header_ptr;
+ u16 bios_header_offset, pll_info_offset;
+ PLL_BLOCK pll;
- if ((err = pci_enable_device(pdev))) {
- printk("radeonfb: cannot enable device\n");
- kfree (rinfo);
- return -ENODEV;
- }
- }
+ if (bios_seg) {
+ bios_header = bios_seg + 0x48L;
+ header_ptr = bios_header;
+
+ bios_header_offset = readw(header_ptr);
+ bios_header = bios_seg + bios_header_offset;
+ bios_header += 0x30;
+
+ header_ptr = bios_header;
+ pll_info_offset = readw(header_ptr);
+ header_ptr = bios_seg + pll_info_offset;
+
+ memcpy_fromio(&pll, header_ptr, 50);
+
+ /* Consider ref clock to be sane between 1000 and 5000,
+ * just in case we tapped the wrong BIOS...
+ */
+ if (pll.PCLK_ref_freq < 1000 || pll.PCLK_ref_freq > 5000)
+ goto use_defaults;
- /* set base addrs */
- rinfo->fb_base_phys = pci_resource_start (pdev, 0);
- rinfo->mmio_base_phys = pci_resource_start (pdev, 2);
+ rinfo->pll.xclk = (u32)pll.XCLK;
+ rinfo->pll.ref_clk = (u32)pll.PCLK_ref_freq;
+ rinfo->pll.ref_div = (u32)pll.PCLK_ref_divider;
+ rinfo->pll.ppll_min = pll.PCLK_min_freq;
+ rinfo->pll.ppll_max = pll.PCLK_max_freq;
- /* request the mem regions */
- if (!request_mem_region (rinfo->fb_base_phys,
- pci_resource_len(pdev, 0), "radeonfb")) {
- printk ("radeonfb: cannot reserve FB region\n");
- kfree (rinfo);
- return -ENODEV;
- }
+ printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from BIOS\n",
+ rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
+ } else {
+#ifdef CONFIG_ALL_PPC
+ if (radeon_read_OF(rinfo)) {
+ unsigned int tmp, Nx, M, ref_div, xclk;
- if (!request_mem_region (rinfo->mmio_base_phys,
- pci_resource_len(pdev, 2), "radeonfb")) {
- printk ("radeonfb: cannot reserve MMIO region\n");
- release_mem_region (rinfo->fb_base_phys,
- pci_resource_len(pdev, 0));
- kfree (rinfo);
- return -ENODEV;
- }
+ tmp = INPLL(M_SPLL_REF_FB_DIV);
+ ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
- /* map the regions */
- rinfo->mmio_base = (unsigned long)ioremap (rinfo->mmio_base_phys,
- RADEON_REGSIZE);
- if (!rinfo->mmio_base) {
- printk ("radeonfb: cannot map MMIO\n");
- release_mem_region (rinfo->mmio_base_phys,
- pci_resource_len(pdev, 2));
- release_mem_region (rinfo->fb_base_phys,
- pci_resource_len(pdev, 0));
- kfree (rinfo);
- return -ENODEV;
- }
+ Nx = (tmp & 0xff00) >> 8;
+ M = (tmp & 0xff);
+ xclk = ((((2 * Nx * rinfo->pll.ref_clk) + (M)) /
+ (2 * M)));
- rinfo->chipset = pdev->device;
+ rinfo->pll.xclk = xclk;
+ rinfo->pll.ref_div = ref_div;
+ rinfo->pll.ppll_min = 12000;
+ rinfo->pll.ppll_max = 35000;
- /* chipset */
- switch (pdev->device) {
- case PCI_DEVICE_ID_RADEON_QD:
- strcpy(rinfo->name, "Radeon QD ");
- break;
- case PCI_DEVICE_ID_RADEON_QE:
- strcpy(rinfo->name, "Radeon QE ");
- break;
- case PCI_DEVICE_ID_RADEON_QF:
- strcpy(rinfo->name, "Radeon QF ");
- break;
- case PCI_DEVICE_ID_RADEON_QG:
- strcpy(rinfo->name, "Radeon QG ");
- break;
- case PCI_DEVICE_ID_RADEON_QY:
- strcpy(rinfo->name, "Radeon QY VE ");
- rinfo->hasCRTC2 = 1;
- break;
- case PCI_DEVICE_ID_RADEON_QZ:
- strcpy(rinfo->name, "Radeon QZ VE ");
- rinfo->hasCRTC2 = 1;
- break;
- case PCI_DEVICE_ID_RADEON_QW:
- strcpy(rinfo->name, "Radeon 7500 QW ");
- rinfo->hasCRTC2 = 1;
- break;
- case PCI_DEVICE_ID_RADEON_QL:
- strcpy(rinfo->name, "Radeon 8500 QL ");
- rinfo->hasCRTC2 = 1;
- break;
- case PCI_DEVICE_ID_RADEON_LW:
- strcpy(rinfo->name, "Radeon M7 LW ");
- rinfo->hasCRTC2 = 1;
- break;
- case PCI_DEVICE_ID_RADEON_LY:
- strcpy(rinfo->name, "Radeon M6 LY ");
- rinfo->hasCRTC2 = 1;
- break;
- case PCI_DEVICE_ID_RADEON_LZ:
- strcpy(rinfo->name, "Radeon M6 LZ ");
- rinfo->hasCRTC2 = 1;
- break;
- case PCI_DEVICE_ID_RADEON_PM:
- strcpy(rinfo->name, "Radeon P/M ");
- rinfo->hasCRTC2 = 1;
- default:
- return -ENODEV;
+ printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from OF\n",
+ rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
+
+ return;
+ }
+#endif
+use_defaults:
+ /* No BIOS or BIOS not found, use defaults
+ *
+ * NOTE: Those defaults settings are rather "randomly" picked from
+ * informations we found so far, but we would really need some
+ * better mecanism to get them. Recent XFree can +/- probe for
+ * the proper clocks.
+ */
+ switch (rinfo->arch) {
+ case RADEON_RV200:
+ rinfo->pll.ppll_max = 35000;
+ rinfo->pll.ppll_min = 12000;
+ rinfo->pll.xclk = 23000;
+ rinfo->pll.ref_div = 12;
+ rinfo->pll.ref_clk = 2700;
+ break;
+ case RADEON_R200:
+ rinfo->pll.ppll_max = 35000;
+ rinfo->pll.ppll_min = 12000;
+ rinfo->pll.xclk = 27500;
+ rinfo->pll.ref_div = 12;
+ rinfo->pll.ref_clk = 2700;
+ break;
+ case RADEON_RV250:
+ rinfo->pll.ppll_max = 35000;
+ rinfo->pll.ppll_min = 12000;
+ rinfo->pll.xclk = 25000;
+ rinfo->pll.ref_div = 12;
+ rinfo->pll.ref_clk = 2700;
+ break;
+ case RADEON_R300:
+ rinfo->pll.ppll_max = 40000;
+ rinfo->pll.ppll_min = 20000;
+ rinfo->pll.xclk = 27000;
+ rinfo->pll.ref_div = 12;
+ rinfo->pll.ref_clk = 2700;
+ break;
+ case RADEON_R100:
+ default:
+ rinfo->pll.ppll_max = 35000;
+ rinfo->pll.ppll_min = 12000;
+ rinfo->pll.xclk = 16600;
+ rinfo->pll.ref_div = 67;
+ rinfo->pll.ref_clk = 2700;
+ break;
+ }
+
+ printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d defaults\n",
+ rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
}
+}
- /* framebuffer size */
- tmp = INREG(CONFIG_MEMSIZE);
- /* mem size is bits [28:0], mask off the rest */
- rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
+static void radeon_get_moninfo (struct radeonfb_info *rinfo)
+{
+ u32 tmp = INREG(RADEON_BIOS_4_SCRATCH);
- /* According to XFree86 4.2.0, some production M6's return 0
- for 8MB. */
- if (rinfo->video_ram == 0 &&
- (pdev->device == PCI_DEVICE_ID_RADEON_LY ||
- pdev->device == PCI_DEVICE_ID_RADEON_LZ)) {
- rinfo->video_ram = 8192 * 1024;
- }
+ if (force_dfp) {
+ printk("radeonfb: forcing DFP\n");
+ rinfo->dviDisp_type = MT_DFP;
+ return;
+ } else if (force_crt) {
+ printk("radeonfb: forcing CRT\n");
+ rinfo->dviDisp_type = MT_NONE;
+ rinfo->crtDisp_type = MT_CRT;
+ return;
+ }
- /* ram type */
- tmp = INREG(MEM_SDRAM_MODE_REG);
- switch ((MEM_CFG_TYPE & tmp) >> 30) {
- case 0:
- /* SDR SGRAM (2:1) */
- strcpy(rinfo->ram_type, "SDR SGRAM");
- rinfo->ram.ml = 4;
- rinfo->ram.mb = 4;
- rinfo->ram.trcd = 1;
- rinfo->ram.trp = 2;
- rinfo->ram.twr = 1;
- rinfo->ram.cl = 2;
- rinfo->ram.loop_latency = 16;
- rinfo->ram.rloop = 16;
-
- break;
- case 1:
- /* DDR SGRAM */
- strcpy(rinfo->ram_type, "DDR SGRAM");
- rinfo->ram.ml = 4;
- rinfo->ram.mb = 4;
- rinfo->ram.trcd = 3;
- rinfo->ram.trp = 3;
- rinfo->ram.twr = 2;
- rinfo->ram.cl = 3;
- rinfo->ram.tr2w = 1;
- rinfo->ram.loop_latency = 16;
- rinfo->ram.rloop = 16;
-
- break;
- default:
- /* 64-bit SDR SGRAM */
- strcpy(rinfo->ram_type, "SDR SGRAM 64");
- rinfo->ram.ml = 4;
- rinfo->ram.mb = 8;
- rinfo->ram.trcd = 3;
- rinfo->ram.trp = 3;
- rinfo->ram.twr = 1;
- rinfo->ram.cl = 3;
- rinfo->ram.tr2w = 1;
- rinfo->ram.loop_latency = 17;
- rinfo->ram.rloop = 17;
-
- break;
- }
-
- rinfo->bios_seg = radeon_find_rom(rinfo);
- radeon_get_pllinfo(rinfo, rinfo->bios_seg);
-
- RTRACE("radeonfb: probed %s %dk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024));
-
-#if !defined(__powerpc__)
- radeon_get_moninfo(rinfo);
-#else
- switch (pdev->device) {
- case PCI_DEVICE_ID_RADEON_LW:
- case PCI_DEVICE_ID_RADEON_LY:
- case PCI_DEVICE_ID_RADEON_LZ:
- case PCI_DEVICE_ID_RADEON_PM:
- rinfo->dviDisp_type = MT_LCD;
- break;
- default:
- radeon_get_moninfo(rinfo);
- break;
- }
-#endif
-
- radeon_get_EDID(rinfo);
-
- if ((rinfo->dviDisp_type == MT_DFP) || (rinfo->dviDisp_type == MT_LCD) ||
- (rinfo->crtDisp_type == MT_DFP)) {
- if (!radeon_get_dfpinfo(rinfo)) {
- iounmap ((void*)rinfo->mmio_base);
- release_mem_region (rinfo->mmio_base_phys,
- pci_resource_len(pdev, 2));
- release_mem_region (rinfo->fb_base_phys,
- pci_resource_len(pdev, 0));
- kfree (rinfo);
- return -ENODEV;
- }
- }
-
- rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys,
- rinfo->video_ram);
- if (!rinfo->fb_base) {
- printk ("radeonfb: cannot map FB\n");
- iounmap ((void*)rinfo->mmio_base);
- release_mem_region (rinfo->mmio_base_phys,
- pci_resource_len(pdev, 2));
- release_mem_region (rinfo->fb_base_phys,
- pci_resource_len(pdev, 0));
- kfree (rinfo);
- return -ENODEV;
- }
-
- /* XXX turn off accel for now, blts aren't working right */
- noaccel = 1;
-
- /* currcon not yet configured, will be set by first switch */
- rinfo->currcon = -1;
-
- /* set all the vital stuff */
- radeon_set_fbinfo (rinfo);
-
- /* save current mode regs before we switch into the new one
- * so we can restore this upon __exit
- */
- radeon_save_state (rinfo, &rinfo->init_state);
-
- /* init palette */
- for (i=0; i<16; i++) {
- j = color_table[i];
- rinfo->palette[i].red = default_red[j];
- rinfo->palette[i].green = default_grn[j];
- rinfo->palette[i].blue = default_blu[j];
- }
-
- pci_set_drvdata(pdev, rinfo);
- rinfo->next = board_list;
- board_list = rinfo;
-
- if (register_framebuffer ((struct fb_info *) rinfo) < 0) {
- printk ("radeonfb: could not register framebuffer\n");
- iounmap ((void*)rinfo->fb_base);
- iounmap ((void*)rinfo->mmio_base);
- release_mem_region (rinfo->mmio_base_phys,
- pci_resource_len(pdev, 2));
- release_mem_region (rinfo->fb_base_phys,
- pci_resource_len(pdev, 0));
- kfree (rinfo);
- return -ENODEV;
- }
-
- if (!noaccel) {
- /* initialize the engine */
- radeon_engine_init (rinfo);
- }
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (rinfo->dviDisp_type == MT_LCD)
- register_backlight_controller(&radeon_backlight_controller,
- rinfo, "ati");
-#endif
-
-#ifdef CONFIG_PMAC_PBOOK
- if (rinfo->dviDisp_type == MT_LCD) {
- rinfo->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
- pmu_register_sleep_notifier(&radeon_sleep_notifier);
- }
-#endif
-
- printk ("radeonfb: ATI %s %s %d MB\n", rinfo->name, rinfo->ram_type,
- (rinfo->video_ram/(1024*1024)));
-
- if (rinfo->hasCRTC2) {
- printk("radeonfb: DVI port %s monitor connected\n",
- GET_MON_NAME(rinfo->dviDisp_type));
- printk("radeonfb: CRT port %s monitor connected\n",
- GET_MON_NAME(rinfo->crtDisp_type));
- } else {
- printk("radeonfb: CRT port %s monitor connected\n",
- GET_MON_NAME(rinfo->crtDisp_type));
- }
-
- RTRACE("radeonfb_pci_register END\n");
-
- return 0;
-}
-
-
-
-static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
-{
- struct radeonfb_info *rinfo = pci_get_drvdata(pdev);
-
- if (!rinfo)
- return;
-
- /* restore original state */
- radeon_write_mode (rinfo, &rinfo->init_state);
-
- unregister_framebuffer ((struct fb_info *) rinfo);
-
- iounmap ((void*)rinfo->mmio_base);
- iounmap ((void*)rinfo->fb_base);
-
- release_mem_region (rinfo->mmio_base_phys,
- pci_resource_len(pdev, 2));
- release_mem_region (rinfo->fb_base_phys,
- pci_resource_len(pdev, 0));
-
- kfree (rinfo);
-}
-
-
-
-static char *radeon_find_rom(struct radeonfb_info *rinfo)
-{
-#if defined(__i386__)
- u32 segstart;
- char *rom_base;
- char *rom;
- int stage;
- int i,j;
- char aty_rom_sig[] = "761295520";
- char *radeon_sig[] = {
- "RG6",
- "RADEON"
- };
-
- for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
-
- stage = 1;
-
- rom_base = (char *)ioremap(segstart, 0x1000);
-
- if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
- stage = 2;
-
-
- if (stage != 2) {
- iounmap(rom_base);
- continue;
- }
-
- rom = rom_base;
-
- for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) {
- if (aty_rom_sig[0] == *rom)
- if (strncmp(aty_rom_sig, rom,
- strlen(aty_rom_sig)) == 0)
- stage = 3;
- rom++;
- }
- if (stage != 3) {
- iounmap(rom_base);
- continue;
- }
- rom = rom_base;
-
- for (i = 0; (i < 512) && (stage != 4); i++) {
- for(j = 0;j < sizeof(radeon_sig)/sizeof(char *);j++) {
- if (radeon_sig[j][0] == *rom)
- if (strncmp(radeon_sig[j], rom,
- strlen(radeon_sig[j])) == 0) {
- stage = 4;
- break;
- }
- }
- rom++;
- }
- if (stage != 4) {
- iounmap(rom_base);
- continue;
- }
-
- return rom_base;
- }
-#endif
- return NULL;
-}
-
-
-
-
-static void radeon_get_pllinfo(struct radeonfb_info *rinfo, char *bios_seg)
-{
- void *bios_header;
- void *header_ptr;
- u16 bios_header_offset, pll_info_offset;
- PLL_BLOCK pll;
-
- if (bios_seg) {
- bios_header = bios_seg + 0x48L;
- header_ptr = bios_header;
-
- bios_header_offset = readw(header_ptr);
- bios_header = bios_seg + bios_header_offset;
- bios_header += 0x30;
-
- header_ptr = bios_header;
- pll_info_offset = readw(header_ptr);
- header_ptr = bios_seg + pll_info_offset;
-
- memcpy_fromio(&pll, header_ptr, 50);
-
- rinfo->pll.xclk = (u32)pll.XCLK;
- rinfo->pll.ref_clk = (u32)pll.PCLK_ref_freq;
- rinfo->pll.ref_div = (u32)pll.PCLK_ref_divider;
- rinfo->pll.ppll_min = pll.PCLK_min_freq;
- rinfo->pll.ppll_max = pll.PCLK_max_freq;
-
- printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from BIOS\n",
- rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
- } else {
-#ifdef CONFIG_ALL_PPC
- if (radeon_read_OF(rinfo)) {
- unsigned int tmp, Nx, M, ref_div, xclk;
-
- tmp = INPLL(M_SPLL_REF_FB_DIV);
- ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
-
- Nx = (tmp & 0xff00) >> 8;
- M = (tmp & 0xff);
- xclk = ((((2 * Nx * rinfo->pll.ref_clk) + (M)) /
- (2 * M)));
-
- rinfo->pll.xclk = xclk;
- rinfo->pll.ref_div = ref_div;
- rinfo->pll.ppll_min = 12000;
- rinfo->pll.ppll_max = 35000;
-
- printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from OF\n",
- rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
-
- return;
- }
-#endif
- /* no BIOS or BIOS not found, use defaults */
- switch (rinfo->chipset) {
- case PCI_DEVICE_ID_RADEON_QW:
- rinfo->pll.ppll_max = 35000;
- rinfo->pll.ppll_min = 12000;
- rinfo->pll.xclk = 23000;
- rinfo->pll.ref_div = 12;
- rinfo->pll.ref_clk = 2700;
- break;
- case PCI_DEVICE_ID_RADEON_QL:
- rinfo->pll.ppll_max = 35000;
- rinfo->pll.ppll_min = 12000;
- rinfo->pll.xclk = 27500;
- rinfo->pll.ref_div = 12;
- rinfo->pll.ref_clk = 2700;
- break;
- case PCI_DEVICE_ID_RADEON_QD:
- case PCI_DEVICE_ID_RADEON_QE:
- case PCI_DEVICE_ID_RADEON_QF:
- case PCI_DEVICE_ID_RADEON_QG:
- default:
- rinfo->pll.ppll_max = 35000;
- rinfo->pll.ppll_min = 12000;
- rinfo->pll.xclk = 16600;
- rinfo->pll.ref_div = 67;
- rinfo->pll.ref_clk = 2700;
- break;
- }
-
- printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d defaults\n",
- rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
- }
-}
-
-
-static void radeon_get_moninfo (struct radeonfb_info *rinfo)
-{
- unsigned int tmp;
- if (force_dfp) {
- rinfo->dviDisp_type = MT_DFP;
- return;
- }
-
- tmp = INREG(RADEON_BIOS_4_SCRATCH);
-
- if (rinfo->hasCRTC2) {
+ if (rinfo->hasCRTC2 && tmp) {
/* primary DVI port */
if (tmp & 0x08)
rinfo->dviDisp_type = MT_DFP;
@@ -1279,7 +1225,29 @@
}
}
-
+#ifdef CONFIG_ALL_PPC
+static int radeon_get_EDID_OF(struct radeonfb_info *rinfo)
+{
+ struct device_node *dp;
+ unsigned char *pedid = NULL;
+ static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL };
+ int i;
+
+ dp = pci_device_to_OF_node(rinfo->pdev);
+ while (dp != NULL) {
+ for (i = 0; propnames[i] != NULL; ++i) {
+ pedid = (unsigned char *)
+ get_property(dp, propnames[i], NULL);
+ if (pedid != NULL) {
+ rinfo->EDID = pedid;
+ return 1;
+ }
+ }
+ dp = dp->child;
+ }
+ return 0;
+}
+#endif /* CONFIG_ALL_PPC */
static void radeon_get_EDID(struct radeonfb_info *rinfo)
{
@@ -1291,29 +1259,83 @@
#endif
}
-
#ifdef CONFIG_ALL_PPC
-static int radeon_get_EDID_OF(struct radeonfb_info *rinfo)
-{
- struct device_node *dp;
- unsigned char *pedid = NULL;
+#undef SET_MC_FB_FROM_APERTURE
+static void
+radeon_fixup_apertures(struct radeonfb_info *rinfo)
+{
+ u32 save_crtc_gen_cntl, save_crtc2_gen_cntl;
+ u32 save_crtc_ext_cntl;
+ u32 aper_base, aper_size;
+ u32 agp_base;
- dp = pci_device_to_OF_node(rinfo->pdev);
- pedid = (unsigned char *) get_property(dp, "DFP,EDID", 0);
- if (!pedid)
- pedid = (unsigned char *) get_property(dp, "LCD,EDID", 0);
- if (!pedid)
- pedid = (unsigned char *) get_property(dp, "EDID", 0);
+ /* First, we disable display to avoid interfering */
+ if (rinfo->hasCRTC2) {
+ save_crtc2_gen_cntl = INREG(CRTC2_GEN_CNTL);
+ OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl | CRTC2_DISP_REQ_EN_B);
+ }
+ save_crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
+ save_crtc_ext_cntl = INREG(CRTC_EXT_CNTL);
+
+ OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl | CRTC_DISPLAY_DIS);
+ OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl | CRTC_DISP_REQ_EN_B);
+ mdelay(100);
+
+ aper_base = INREG(CONFIG_APER_0_BASE);
+ aper_size = INREG(CONFIG_APER_SIZE);
+
+#ifdef SET_MC_FB_FROM_APERTURE
+ /* Set framebuffer to be at the same address as set in PCI BAR */
+ OUTREG(MC_FB_LOCATION,
+ ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16));
+ rinfo->fb_local_base = aper_base;
+#else
+ OUTREG(MC_FB_LOCATION, 0x7fff0000);
+ rinfo->fb_local_base = 0;
+#endif
+ agp_base = aper_base + aper_size;
+ if (agp_base & 0xf0000000)
+ agp_base = (aper_base | 0x0fffffff) + 1;
+
+ /* Set AGP to be just after the framebuffer on a 256Mb boundary. This
+ * assumes the FB isn't mapped to 0xf0000000 or above, but this is
+ * always the case on PPCs afaik.
+ */
+#ifdef SET_MC_FB_FROM_APERTURE
+ OUTREG(MC_AGP_LOCATION, 0xffff0000 | (agp_base >> 16));
+#else
+ OUTREG(MC_AGP_LOCATION, 0xffffe000);
+#endif
- if (pedid) {
- rinfo->EDID = pedid;
- return 1;
- } else
- return 0;
+ /* Fixup the display base addresses & engine offsets while we
+ * are at it as well
+ */
+#ifdef SET_MC_FB_FROM_APERTURE
+ OUTREG(DISPLAY_BASE_ADDR, aper_base);
+ if (rinfo->hasCRTC2)
+ OUTREG(CRTC2_DISPLAY_BASE_ADDR, aper_base);
+#else
+ OUTREG(DISPLAY_BASE_ADDR, 0);
+ if (rinfo->hasCRTC2)
+ OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0);
+#endif
+ mdelay(100);
+
+ /* Restore display settings */
+ OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl);
+ OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl);
+ if (rinfo->hasCRTC2)
+ OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl);
+
+#if 0
+ printk("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n",
+ aper_base,
+ ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16),
+ 0xffff0000 | (agp_base >> 16));
+#endif
}
#endif /* CONFIG_ALL_PPC */
-
static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo)
{
unsigned char *block = rinfo->EDID;
@@ -1344,6 +1366,15 @@
rinfo->vAct_high = 1;
}
+ RTRACE("hOver_plus = %d\t hSync_width = %d\n", rinfo->hOver_plus,
+ rinfo->hSync_width);
+ RTRACE("vOver_plus = %d\t vSync_width = %d\n", rinfo->vOver_plus,
+ rinfo->vSync_width);
+ RTRACE("hblank = %d\t vblank = %d\n", rinfo->hblank,
+ rinfo->vblank);
+ RTRACE("sync = %d\n", rinfo->synct);
+ RTRACE("misc = %d\n", rinfo->misc);
+ RTRACE("clock = %d\n", rinfo->clock);
printk("radeonfb: detected DFP panel size from EDID: %dx%d\n",
rinfo->panel_xres, rinfo->panel_yres);
@@ -1352,11 +1383,13 @@
return 1;
}
-
static void radeon_update_default_var(struct radeonfb_info *rinfo)
{
struct fb_var_screeninfo *var = &radeonfb_default_var;
+ /*
+ * Update default var to match the lcd monitor's native resolution
+ */
var->xres = rinfo->panel_xres;
var->yres = rinfo->panel_yres;
var->xres_virtual = rinfo->panel_xres;
@@ -1371,12 +1404,10 @@
var->hsync_len = rinfo->hSync_width;
var->vsync_len = rinfo->vSync_width;
var->sync = 0;
- if (rinfo->synct == 3) {
- if (rinfo->hAct_high)
- var->sync |= FB_SYNC_HOR_HIGH_ACT;
- if (rinfo->vAct_high)
- var->sync |= FB_SYNC_VERT_HIGH_ACT;
- }
+ if (rinfo->hAct_high)
+ var->sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (rinfo->vAct_high)
+ var->sync |= FB_SYNC_VERT_HIGH_ACT;
var->vmode = 0;
if (rinfo->interlaced)
@@ -1385,25 +1416,65 @@
rinfo->use_default_var = 1;
}
-
-static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo)
-{
- char *fpbiosstart, *tmp, *tmp0;
- char stmp[30];
- int i;
-
- if (!rinfo->bios_seg)
- return 0;
-
- if (!(fpbiosstart = rinfo->bios_seg + readw(rinfo->bios_seg + 0x48))) {
+/* Copied from XFree86 4.3 --BenH */
+static int
+radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo, unsigned char *fpbiosstart)
+{
+ unsigned char *tmp;
+ unsigned short offset;
+
+ offset = readw(fpbiosstart + 0x34);
+ if (offset != 0)
+ offset = readw(rinfo->bios_seg + offset + 2);
+ if (offset == 0) {
printk("radeonfb: Failed to detect DFP panel info using BIOS\n");
return 0;
}
+ tmp = rinfo->bios_seg + offset;
+
+ /* This is an EDID block */
+ rinfo->clock = readw(tmp);
+ rinfo->panel_xres = (readb(tmp + 2) + ((readb(tmp + 4) & 0xf0) << 4));
+ rinfo->hblank = (readb(tmp + 3) + ((readb(tmp + 4) & 0x0f) << 8));
+ rinfo->panel_yres = (readb(tmp + 5) + ((readb(tmp + 7) & 0xf0) << 4));
+ rinfo->vblank = (readb(tmp + 6) + ((readb(tmp + 7) & 0x0f) << 8));
+ rinfo->hOver_plus = (readb(tmp + 8) + ((readb(tmp + 11) & 0xc0) << 2));
+ rinfo->hSync_width = (readb(tmp + 9) + ((readb(tmp + 11) & 0x30) << 4));
+ rinfo->vOver_plus = ((readb(tmp + 10) >> 4) + ((readb(tmp + 11) & 0x0c) << 2));
+ rinfo->vSync_width = ((readb(tmp + 10) & 0x0f) + ((readb(tmp + 11) & 0x03) << 4));
+ rinfo->interlaced = ((readb(tmp + 17) & 0x80) >> 7);
+ rinfo->synct = ((readb(tmp + 17) & 0x18) >> 3);
+ rinfo->misc = ((readb(tmp + 17) & 0x06) >> 1);
+ rinfo->hAct_high = rinfo->vAct_high = 0;
+ if (rinfo->synct == 3) {
+ if (rinfo->misc & 2)
+ rinfo->hAct_high = 1;
+ if (rinfo->misc & 1)
+ rinfo->vAct_high = 1;
+ }
+
+ printk("radeonfb: detected DFP panel size from BIOS: %dx%d\n",
+ rinfo->panel_xres, rinfo->panel_yres);
+
+ rinfo->got_dfpinfo = 1;
+ return 1;
+}
- if (!(tmp = rinfo->bios_seg + readw(fpbiosstart + 0x40))) {
- printk("radeonfb: Failed to detect DFP panel info using BIOS\n");
+
+static int
+radeon_get_lcdinfo_BIOS(struct radeonfb_info *rinfo, unsigned char *fpbiosstart)
+{
+ unsigned char *tmp, *tmp0;
+ unsigned char stmp[30];
+ unsigned short offset;
+ int i;
+
+ offset = readw(fpbiosstart + 0x40);
+ if (offset == 0) {
+ printk("radeonfb: Failed to detect LCD panel info using BIOS\n");
return 0;
}
+ tmp = rinfo->bios_seg + offset;
for(i=0; i<24; i++)
stmp[i] = readb(tmp+i+1);
@@ -1411,7 +1482,7 @@
printk("radeonfb: panel ID string: %s\n", stmp);
rinfo->panel_xres = readw(tmp + 25);
rinfo->panel_yres = readw(tmp + 27);
- printk("radeonfb: detected DFP panel size from BIOS: %dx%d\n",
+ printk("radeonfb: detected LCD panel size from BIOS: %dx%d\n",
rinfo->panel_xres, rinfo->panel_yres);
for(i=0; i<20; i++) {
@@ -1427,11 +1498,33 @@
rinfo->vOver_plus = (readw(tmp0+28) & 0x7ff) - readw(tmp0+26);
rinfo->vSync_width = (readw(tmp0+28) & 0xf800) >> 11;
rinfo->clock = readw(tmp0+9);
-
+ /* We don't know that the H/V sync active level should be
+ make the same assumptions as XFree does - High Active */
+ rinfo->vAct_high=1;
+ rinfo->hAct_high=1;
rinfo->got_dfpinfo = 1;
return 1;
}
}
+ return 0;
+}
+
+static int radeon_get_panelinfo_BIOS(struct radeonfb_info *rinfo)
+{
+ unsigned char *fpbiosstart;
+
+ if (!rinfo->bios_seg)
+ return 0;
+
+ if (!(fpbiosstart = rinfo->bios_seg + readw(rinfo->bios_seg + 0x48))) {
+ printk("radeonfb: Failed to detect DFP panel info using BIOS\n");
+ return 0;
+ }
+
+ if (rinfo->dviDisp_type == MT_LCD)
+ return radeon_get_lcdinfo_BIOS(rinfo, fpbiosstart);
+ else if (rinfo->dviDisp_type == MT_DFP)
+ return radeon_get_dfpinfo_BIOS(rinfo, fpbiosstart);
return 0;
}
@@ -1443,7 +1536,7 @@
unsigned int tmp;
unsigned short a, b;
- if (radeon_get_dfpinfo_BIOS(rinfo))
+ if (radeon_get_panelinfo_BIOS(rinfo))
radeon_update_default_var(rinfo);
if (radeon_dfp_parse_EDID(rinfo))
@@ -1470,11 +1563,6 @@
rinfo->panel_xres = 800;
break;
case 768:
-#if defined(__powerpc__)
- if (rinfo->dviDisp_type == MT_LCD)
- rinfo->panel_xres = 1152;
- else
-#endif
rinfo->panel_xres = 1024;
break;
case 1024:
@@ -1511,42 +1599,363 @@
b = (tmp & FP_CRTC_V_DISP_MASK) >> FP_CRTC_V_DISP_SHIFT;
rinfo->vblank = a - b /* + 24 */ ;
- tmp = INREG(FP_V_SYNC_STRT_WID);
- rinfo->vOver_plus = (unsigned short) (tmp & FP_V_SYNC_STRT_MASK)
- - b + 1;
- rinfo->vSync_width = (unsigned short) ((tmp & FP_V_SYNC_WID_MASK) >>
- FP_V_SYNC_WID_SHIFT);
+ tmp = INREG(FP_V_SYNC_STRT_WID);
+ rinfo->vOver_plus = (unsigned short) (tmp & FP_V_SYNC_STRT_MASK)
+ - b + 1;
+ rinfo->vSync_width = (unsigned short) ((tmp & FP_V_SYNC_WID_MASK) >>
+ FP_V_SYNC_WID_SHIFT);
+
+ /* XXX */
+ /* We should calculate the pixclock as well here... --BenH.
+ */
+
+ return 1;
+ }
+
+ return 1;
+}
+
+static int radeonfb_pci_register (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct radeonfb_info *rinfo;
+ struct radeon_chip_info *rci = &radeon_chip_info[ent->driver_data];
+ u32 tmp;
+ int i, j;
+
+ RTRACE("radeonfb_pci_register BEGIN\n");
+
+ rinfo = kmalloc (sizeof (struct radeonfb_info), GFP_KERNEL);
+ if (!rinfo) {
+ printk ("radeonfb: could not allocate memory\n");
+ return -ENODEV;
+ }
+
+ memset (rinfo, 0, sizeof (struct radeonfb_info));
+
+ rinfo->pdev = pdev;
+ strncpy(rinfo->name, rci->name, 16);
+ rinfo->arch = rci->arch;
+
+ /* enable device */
+ {
+ int err;
+
+ if ((err = pci_enable_device(pdev))) {
+ printk("radeonfb: cannot enable device\n");
+ kfree (rinfo);
+ return -ENODEV;
+ }
+ }
+
+ /* set base addrs */
+ rinfo->fb_base_phys = pci_resource_start (pdev, 0);
+ rinfo->mmio_base_phys = pci_resource_start (pdev, 2);
+
+ /* request the mem regions */
+ if (!request_mem_region (rinfo->fb_base_phys,
+ pci_resource_len(pdev, 0), "radeonfb")) {
+ printk ("radeonfb: cannot reserve FB region\n");
+ kfree (rinfo);
+ return -ENODEV;
+ }
+
+ if (!request_mem_region (rinfo->mmio_base_phys,
+ pci_resource_len(pdev, 2), "radeonfb")) {
+ printk ("radeonfb: cannot reserve MMIO region\n");
+ release_mem_region (rinfo->fb_base_phys,
+ pci_resource_len(pdev, 0));
+ kfree (rinfo);
+ return -ENODEV;
+ }
+
+ /* map the regions */
+ rinfo->mmio_base = (unsigned long) ioremap (rinfo->mmio_base_phys,
+ RADEON_REGSIZE);
+ if (!rinfo->mmio_base) {
+ printk ("radeonfb: cannot map MMIO\n");
+ release_mem_region (rinfo->mmio_base_phys,
+ pci_resource_len(pdev, 2));
+ release_mem_region (rinfo->fb_base_phys,
+ pci_resource_len(pdev, 0));
+ kfree (rinfo);
+ return -ENODEV;
+ }
+
+ rinfo->chipset = pdev->device;
+
+ switch (rinfo->arch) {
+ case RADEON_R100:
+ rinfo->hasCRTC2 = 0;
+ break;
+ default:
+ /* all the rest have it */
+ rinfo->hasCRTC2 = 1;
+ break;
+ }
+
+ if (mirror)
+ printk("radeonfb: mirroring display to CRT\n");
+
+ /* framebuffer size */
+ tmp = INREG(CONFIG_MEMSIZE);
+
+ /* mem size is bits [28:0], mask off the rest */
+ rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
+
+ /* ram type */
+ tmp = INREG(MEM_SDRAM_MODE_REG);
+ switch ((MEM_CFG_TYPE & tmp) >> 30) {
+ case 0:
+ /* SDR SGRAM (2:1) */
+ strcpy(rinfo->ram_type, "SDR SGRAM");
+ rinfo->ram.ml = 4;
+ rinfo->ram.mb = 4;
+ rinfo->ram.trcd = 1;
+ rinfo->ram.trp = 2;
+ rinfo->ram.twr = 1;
+ rinfo->ram.cl = 2;
+ rinfo->ram.loop_latency = 16;
+ rinfo->ram.rloop = 16;
+
+ break;
+ case 1:
+ /* DDR SGRAM */
+ strcpy(rinfo->ram_type, "DDR SGRAM");
+ rinfo->ram.ml = 4;
+ rinfo->ram.mb = 4;
+ rinfo->ram.trcd = 3;
+ rinfo->ram.trp = 3;
+ rinfo->ram.twr = 2;
+ rinfo->ram.cl = 3;
+ rinfo->ram.tr2w = 1;
+ rinfo->ram.loop_latency = 16;
+ rinfo->ram.rloop = 16;
+
+ break;
+ default:
+ /* 64-bit SDR SGRAM */
+ strcpy(rinfo->ram_type, "SDR SGRAM 64");
+ rinfo->ram.ml = 4;
+ rinfo->ram.mb = 8;
+ rinfo->ram.trcd = 3;
+ rinfo->ram.trp = 3;
+ rinfo->ram.twr = 1;
+ rinfo->ram.cl = 3;
+ rinfo->ram.tr2w = 1;
+ rinfo->ram.loop_latency = 17;
+ rinfo->ram.rloop = 17;
+
+ break;
+ }
+
+ rinfo->bios_seg = radeon_find_rom(rinfo);
+ radeon_get_pllinfo(rinfo, rinfo->bios_seg);
+
+ /*
+ * Hack to get around some busted production M6's
+ * reporting no ram
+ */
+ if (rinfo->video_ram == 0) {
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_ATI_RADEON_LY:
+ case PCI_DEVICE_ID_ATI_RADEON_LZ:
+ rinfo->video_ram = 8192 * 1024;
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ RTRACE("radeonfb: probed %s %dk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024));
+
+ RTRACE("BIOS 4 scratch = %x\n", INREG(RADEON_BIOS_4_SCRATCH));
+ RTRACE("FP_GEN_CNTL: %x, FP2_GEN_CNTL: %x\n",
+ INREG(FP_GEN_CNTL), INREG(FP2_GEN_CNTL));
+ RTRACE("TMDS_TRANSMITTER_CNTL: %x, TMDS_CNTL: %x, LVDS_GEN_CNTL: %x\n",
+ INREG(TMDS_TRANSMITTER_CNTL), INREG(TMDS_CNTL), INREG(LVDS_GEN_CNTL));
+ RTRACE("DAC_CNTL: %x, DAC_CNTL2: %x, CRTC_GEN_CNTL: %x\n",
+ INREG(DAC_CNTL), INREG(DAC_CNTL2), INREG(CRTC_GEN_CNTL));
+
+
+#if !defined(__powerpc__)
+ radeon_get_moninfo(rinfo);
+#else
+ switch (rinfo->arch) {
+ case RADEON_M6:
+ case RADEON_M7:
+ case RADEON_M9:
+ /* If forced to no-LCD, we shut down the backlight */
+ if (force_nolcd) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ radeon_set_backlight_enable(0, BACKLIGHT_OFF, rinfo);
+#endif
+ } else {
+ rinfo->dviDisp_type = MT_LCD;
+ break;
+ }
+ /* Fall through */
+ default:
+ radeon_get_moninfo(rinfo);
+ break;
+ }
+#endif
+
+ radeon_get_EDID(rinfo);
+
+ if ((rinfo->dviDisp_type == MT_DFP) || (rinfo->dviDisp_type == MT_LCD) ||
+ (rinfo->crtDisp_type == MT_DFP)) {
+ if (!radeon_get_dfpinfo(rinfo)) {
+ iounmap ((void*)rinfo->mmio_base);
+ release_mem_region (rinfo->mmio_base_phys,
+ pci_resource_len(pdev, 2));
+ release_mem_region (rinfo->fb_base_phys,
+ pci_resource_len(pdev, 0));
+ kfree (rinfo);
+ return -ENODEV;
+ }
+ }
+
+ rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys,
+ rinfo->video_ram);
+ if (!rinfo->fb_base) {
+ printk ("radeonfb: cannot map FB\n");
+ iounmap ((void*)rinfo->mmio_base);
+ release_mem_region (rinfo->mmio_base_phys,
+ pci_resource_len(pdev, 2));
+ release_mem_region (rinfo->fb_base_phys,
+ pci_resource_len(pdev, 0));
+ kfree (rinfo);
+ return -ENODEV;
+ }
+
+ /* currcon not yet configured, will be set by first switch */
+ rinfo->currcon = -1;
+
+ /* On PPC, the firmware sets up a memory mapping that tends
+ * to cause lockups when enabling the engine. We reconfigure
+ * the card internal memory mappings properly
+ */
+#ifdef CONFIG_ALL_PPC
+ radeon_fixup_apertures(rinfo);
+#else
+ rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
+#endif /* CONFIG_ALL_PPC */
+
+ /* save current mode regs before we switch into the new one
+ * so we can restore this upon __exit
+ */
+ radeon_save_state (rinfo, &rinfo->init_state);
+
+ /* init palette */
+ for (i=0; i<16; i++) {
+ j = color_table[i];
+ rinfo->palette[i].red = default_red[j];
+ rinfo->palette[i].green = default_grn[j];
+ rinfo->palette[i].blue = default_blu[j];
+ }
+
+ pci_set_drvdata(pdev, rinfo);
+ rinfo->next = board_list;
+ board_list = rinfo;
+
+ /* set all the vital stuff */
+ radeon_set_fbinfo (rinfo);
+
+ if (register_framebuffer ((struct fb_info *) rinfo) < 0) {
+ printk ("radeonfb: could not register framebuffer\n");
+ iounmap ((void*)rinfo->fb_base);
+ iounmap ((void*)rinfo->mmio_base);
+ release_mem_region (rinfo->mmio_base_phys,
+ pci_resource_len(pdev, 2));
+ release_mem_region (rinfo->fb_base_phys,
+ pci_resource_len(pdev, 0));
+ kfree (rinfo);
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_MTRR
+ rinfo->mtrr_hdl = nomtrr ? -1 : mtrr_add(rinfo->fb_base_phys,
+ rinfo->video_ram,
+ MTRR_TYPE_WRCOMB, 1);
+#endif
- return 1;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (rinfo->dviDisp_type == MT_LCD)
+ register_backlight_controller(&radeon_backlight_controller,
+ rinfo, "ati");
+#endif
+
+ printk ("radeonfb: ATI Radeon %s %s %d MB\n", rinfo->name, rinfo->ram_type,
+ (rinfo->video_ram/(1024*1024)));
+
+ if (rinfo->hasCRTC2) {
+ printk("radeonfb: DVI port %s monitor connected\n",
+ GET_MON_NAME(rinfo->dviDisp_type));
+ printk("radeonfb: CRT port %s monitor connected\n",
+ GET_MON_NAME(rinfo->crtDisp_type));
+ } else {
+ printk("radeonfb: CRT port %s monitor connected\n",
+ GET_MON_NAME(rinfo->crtDisp_type));
}
- return 1;
-}
+#ifdef CONFIG_PMAC_PBOOK
+ if (rinfo->arch == RADEON_M6 ||
+ rinfo->arch == RADEON_M7 ||
+ rinfo->arch == RADEON_M9) {
+ /* Find PM registers in config space */
+ rinfo->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
+
+ /* Enable dynamic PM of chip clocks */
+ radeon_pm_enable_dynamic_mode(rinfo);
+
+ /* Register sleep callbacks */
+ pmu_register_sleep_notifier(&radeon_sleep_notifier);
+ printk("radeonfb: Power Management enabled for Mobility chipsets\n");
+ }
+#endif
+ RTRACE("radeonfb_pci_register END\n");
-#ifdef CONFIG_ALL_PPC
-static int radeon_read_OF (struct radeonfb_info *rinfo)
-{
- struct device_node *dp;
- unsigned int *xtal;
+ return 0;
+}
- dp = pci_device_to_OF_node(rinfo->pdev);
- xtal = (unsigned int *) get_property(dp, "ATY,RefCLK", 0);
- rinfo->pll.ref_clk = *xtal / 10;
+static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
+{
+ struct radeonfb_info *rinfo = pci_get_drvdata(pdev);
+
+ if (!rinfo)
+ return;
+
+ /* restore original state */
+ radeon_write_mode (rinfo, &rinfo->init_state);
+
+#ifdef CONFIG_MTRR
+ if (rinfo->mtrr_hdl >= 0)
+ mtrr_del(rinfo->mtrr_hdl, 0, 0);
+#endif
- if (*xtal)
- return 1;
- else
- return 0;
+ unregister_framebuffer ((struct fb_info *) rinfo);
+
+ iounmap ((void*)rinfo->mmio_base);
+ iounmap ((void*)rinfo->fb_base);
+
+ release_mem_region (rinfo->mmio_base_phys,
+ pci_resource_len(pdev, 2));
+ release_mem_region (rinfo->fb_base_phys,
+ pci_resource_len(pdev, 0));
+
+ kfree (rinfo);
}
-#endif
-static void radeon_engine_init (struct radeonfb_info *rinfo)
+static int radeon_engine_init (struct radeonfb_info *rinfo)
{
- u32 temp;
+ unsigned long temp;
/* disable 3D engine */
OUTREG(RB3D_CNTL, 0);
@@ -1554,25 +1963,33 @@
radeon_engine_reset ();
radeon_fifo_wait (1);
- OUTREG(DSTCACHE_MODE, 0);
+ if (rinfo->arch != RADEON_R300)
+ OUTREG(RB2D_DSTCACHE_MODE, 0);
- /* XXX */
- rinfo->pitch = ((rinfo->xres * (rinfo->bpp / 8) + 0x3f)) >> 6;
+ radeon_fifo_wait (3);
+ /* We re-read MC_FB_LOCATION from card as it can have been
+ * modified by XFree drivers (ouch !)
+ */
+ rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
- radeon_fifo_wait (1);
- temp = INREG(DEFAULT_PITCH_OFFSET);
- OUTREG(DEFAULT_PITCH_OFFSET, ((temp & 0xc0000000) |
- (rinfo->pitch << 0x16)));
+ OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) |
+ (rinfo->fb_local_base >> 10));
+ OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
+ OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
radeon_fifo_wait (1);
+#if defined(__BIG_ENDIAN)
+ OUTREGP(DP_DATATYPE, HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN);
+#else
OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
-
+#endif
radeon_fifo_wait (1);
OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX |
DEFAULT_SC_BOTTOM_MAX));
temp = radeon_get_dstbpp(rinfo->depth);
rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS);
+
radeon_fifo_wait (1);
OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
GMC_BRUSH_SOLID_COLOR |
@@ -1596,6 +2013,8 @@
OUTREG(DP_WRITE_MSK, 0xffffffff);
radeon_engine_idle ();
+
+ return 0;
}
@@ -1635,66 +2054,35 @@
disp = &rinfo->disp;
disp->var = radeonfb_default_var;
-#if defined(__powerpc__)
- if (rinfo->dviDisp_type == MT_LCD) {
- if (mac_vmode_to_var(VMODE_1152_768_60, CMODE_8, &disp->var))
- disp->var = radeonfb_default_var;
- }
-#endif
-
- rinfo->depth = var_to_depth(&disp->var);
- rinfo->bpp = disp->var.bits_per_pixel;
+ /* We must initialize disp before calling fb_find_mode, as the later
+ * will cause an implicit call to radeonfb_set_var that could crash
+ * if disp is NULL
+ */
info->disp = disp;
-
- radeon_set_dispsw (rinfo, disp);
-
- if (noaccel)
- disp->scrollmode = SCROLL_YREDRAW;
- else
- disp->scrollmode = 0;
-
rinfo->currcon_display = disp;
- if ((radeon_init_disp_var (rinfo)) < 0)
- return -1;
-
- return 0;
-}
-
-
-
-static int radeon_init_disp_var (struct radeonfb_info *rinfo)
-{
#ifndef MODULE
if (mode_option)
- fb_find_mode (&rinfo->disp.var, &rinfo->info, mode_option,
+ fb_find_mode (&disp->var, &rinfo->info, mode_option,
NULL, 0, NULL, 8);
else
#endif
-#if defined(__powerpc__)
- if (rinfo->dviDisp_type == MT_LCD) {
- if (mac_vmode_to_var(VMODE_1152_768_60, CMODE_8, &rinfo->disp.var))
- rinfo->disp.var = radeonfb_default_var;
- }
- else
-#endif
- if (rinfo->use_default_var)
- /* We will use the modified default far */
- rinfo->disp.var = radeonfb_default_var;
- else
-
- fb_find_mode (&rinfo->disp.var, &rinfo->info, "640x480-8@60",
+ if (!rinfo->use_default_var)
+ fb_find_mode (&disp->var, &rinfo->info, "640x480-8@60",
NULL, 0, NULL, 0);
- if (noaccel)
- rinfo->disp.var.accel_flags &= ~FB_ACCELF_TEXT;
- else
- rinfo->disp.var.accel_flags |= FB_ACCELF_TEXT;
-
- return 0;
-}
+ disp->var.accel_flags |= FB_ACCELF_TEXT;
+
+ /* Do we need that below ? ... */
+ rinfo->depth = var_to_depth(&disp->var);
+ rinfo->bpp = disp->var.bits_per_pixel;
+ /* Apply that dawn mode ! */
+ radeon_do_set_var(&disp->var, -1, 0, info);
+
+ return 0;
+}
static void radeon_set_dispsw (struct radeonfb_info *rinfo, struct display *disp)
@@ -1717,43 +2105,58 @@
switch (disp->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 8:
- disp->dispsw = &fbcon_cfb8;
disp->visual = FB_VISUAL_PSEUDOCOLOR;
- disp->line_length = disp->var.xres_virtual;
+ disp->dispsw = accel ? &fbcon_radeon8 : &fbcon_cfb8;
+ if (accel)
+ disp->line_length = (disp->var.xres_virtual + 0x3f) & ~0x3f;
+ else
+ disp->line_length = disp->var.xres_virtual;
break;
-#endif
+#endif /* FBCON_HAS_CFB8 */
+
#ifdef FBCON_HAS_CFB16
case 16:
- disp->dispsw = &fbcon_cfb16;
+ disp->dispsw = accel ? &fbcon_radeon16 : &fbcon_cfb16;
disp->dispsw_data = &rinfo->con_cmap.cfb16;
disp->visual = FB_VISUAL_DIRECTCOLOR;
- disp->line_length = disp->var.xres_virtual * 2;
+ if (accel)
+ disp->line_length = (disp->var.xres_virtual * 2 + 0x3f) & ~0x3f;
+ else
+ disp->line_length = disp->var.xres_virtual * 2;
break;
-#endif
-#ifdef FBCON_HAS_CFB32
+#endif /* FBCON_HAS_CFB16 */
+
+#ifdef FBCON_HAS_CFB24
case 24:
disp->dispsw = &fbcon_cfb24;
disp->dispsw_data = &rinfo->con_cmap.cfb24;
disp->visual = FB_VISUAL_DIRECTCOLOR;
- disp->line_length = disp->var.xres_virtual * 4;
+ if (accel)
+ disp->line_length = (disp->var.xres_virtual * 3 + 0x3f) & ~0x3f;
+ else
+ disp->line_length = disp->var.xres_virtual * 3;
break;
-#endif
+#endif /* FBCON_HAS_CFB24 */
+
#ifdef FBCON_HAS_CFB32
case 32:
- disp->dispsw = &fbcon_cfb32;
+ disp->dispsw = accel ? &fbcon_radeon32 : &fbcon_cfb32;
disp->dispsw_data = &rinfo->con_cmap.cfb32;
disp->visual = FB_VISUAL_DIRECTCOLOR;
- disp->line_length = disp->var.xres_virtual * 4;
+ if (accel)
+ disp->line_length = (disp->var.xres_virtual * 4 + 0x3f) & ~0x3f;
+ else
+ disp->line_length = disp->var.xres_virtual * 4;
break;
-#endif
+#endif /* FBCON_HAS_CFB32 */
+
default:
printk ("radeonfb: setting fbcon_dummy renderer\n");
disp->dispsw = &fbcon_dummy;
}
return;
-}
-
+}
static void do_install_cmap(int con, struct fb_info *info)
@@ -1849,7 +2252,7 @@
disp = (con < 0) ? rinfo->info.disp : &fb_display[con];
memset (fix, 0, sizeof (struct fb_fix_screeninfo));
- strcpy (fix->id, rinfo->name);
+ sprintf (fix->id, "ATI Radeon %s", rinfo->name);
fix->smem_start = rinfo->fb_base_phys;
fix->smem_len = rinfo->video_ram;
@@ -1887,19 +2290,18 @@
}
-
-static int radeonfb_set_var (struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+static int radeon_do_set_var (struct fb_var_screeninfo *var, int con,
+ int real, struct fb_info *info)
{
struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
struct display *disp;
struct fb_var_screeninfo v;
int nom, den, accel;
- unsigned chgvar = 0;
+ unsigned chgvar = 1;
disp = (con < 0) ? rinfo->info.disp : &fb_display[con];
- accel = var->accel_flags & FB_ACCELF_TEXT;
+ accel = (noaccel == 0) && ((var->accel_flags & FB_ACCELF_TEXT) != 0);
if (con >= 0) {
chgvar = ((disp->var.xres != var->xres) ||
@@ -1909,9 +2311,12 @@
(disp->var.bits_per_pixel != var->bits_per_pixel) ||
memcmp (&disp->var.red, &var->red, sizeof (var->red)) ||
memcmp (&disp->var.green, &var->green, sizeof (var->green)) ||
- memcmp (&disp->var.blue, &var->blue, sizeof (var->blue)));
+ memcmp (&disp->var.blue, &var->blue, sizeof (var->blue)) ||
+ var->accel_flags != disp->var.accel_flags);
}
+try_again:
+
memcpy (&v, var, sizeof (v));
switch (v.bits_per_pixel) {
@@ -1935,7 +2340,10 @@
#ifdef FBCON_HAS_CFB8
case 8:
nom = den = 1;
- disp->line_length = v.xres_virtual;
+ if (accel)
+ disp->line_length = (v.xres_virtual + 0x3f) & ~0x3f;
+ else
+ disp->line_length = v.xres_virtual;
disp->visual = FB_VISUAL_PSEUDOCOLOR;
v.red.offset = v.green.offset = v.blue.offset = 0;
v.red.length = v.green.length = v.blue.length = 8;
@@ -1947,7 +2355,10 @@
case 15:
nom = 2;
den = 1;
- disp->line_length = v.xres_virtual * 2;
+ if (accel)
+ disp->line_length = (v.xres_virtual * 2 + 0x3f) & ~0x3f;
+ else
+ disp->line_length = v.xres_virtual * 2;
disp->visual = FB_VISUAL_DIRECTCOLOR;
v.red.offset = 10;
v.green.offset = 5;
@@ -1958,7 +2369,10 @@
case 16:
nom = 2;
den = 1;
- disp->line_length = v.xres_virtual * 2;
+ if (accel)
+ disp->line_length = (v.xres_virtual * 2 + 0x3f) & ~0x3f;
+ else
+ disp->line_length = v.xres_virtual * 2;
disp->visual = FB_VISUAL_DIRECTCOLOR;
v.red.offset = 11;
v.green.offset = 5;
@@ -1974,7 +2388,10 @@
case 24:
nom = 4;
den = 1;
- disp->line_length = v.xres_virtual * 3;
+ if (accel)
+ disp->line_length = (v.xres_virtual * 3 + 0x3f) & ~0x3f;
+ else
+ disp->line_length = v.xres_virtual * 3;
disp->visual = FB_VISUAL_DIRECTCOLOR;
v.red.offset = 16;
v.green.offset = 8;
@@ -1987,7 +2404,10 @@
case 32:
nom = 4;
den = 1;
- disp->line_length = v.xres_virtual * 4;
+ if (accel)
+ disp->line_length = (v.xres_virtual * 4 + 0x3f) & ~0x3f;
+ else
+ disp->line_length = v.xres_virtual * 4;
disp->visual = FB_VISUAL_DIRECTCOLOR;
v.red.offset = 16;
v.green.offset = 8;
@@ -2030,28 +2450,47 @@
default:
return -EINVAL;
}
+
+ /* Set real accel */
+ if (accel)
+ v.accel_flags |= FB_ACCELF_TEXT;
+ else
+ v.accel_flags &= ~FB_ACCELF_TEXT;
memcpy (&disp->var, &v, sizeof (v));
-
+
+ if (real)
+ radeon_load_video_mode (rinfo, &v);
+ if (accel && real) {
+ if (radeon_engine_init(rinfo) < 0) {
+ var->accel_flags &= ~FB_ACCELF_TEXT;
+ goto try_again;
+ }
+ }
+
if (chgvar) {
- radeon_set_dispsw(rinfo, disp);
+ radeon_set_dispsw(rinfo, disp);
- if (noaccel)
+ if (!accel)
disp->scrollmode = SCROLL_YREDRAW;
else
disp->scrollmode = 0;
- if (info && info->changevar)
+ if (info && info->changevar && con >= 0)
info->changevar(con);
}
-
- radeon_load_video_mode (rinfo, &v);
-
- do_install_cmap(con, info);
+
+ if (real)
+ do_install_cmap(con, info);
return 0;
}
+static int radeonfb_set_var (struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ return radeon_do_set_var(var, con, 1, info);
+}
static int radeonfb_get_cmap (struct fb_cmap *cmap, int kspc, int con,
@@ -2107,19 +2546,17 @@
struct fb_info *info)
{
struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
- u32 offset, xoffset, yoffset;
-
- xoffset = (var->xoffset + 7) & ~7;
- yoffset = var->yoffset;
-
- if ((xoffset + var->xres > var->xres_virtual) || (yoffset+var->yres >
- var->yres_virtual))
- return -EINVAL;
+
+ if (((var->xoffset + var->xres) > var->xres_virtual)
+ || ((var->yoffset + var->yres) > var->yres_virtual))
+ return -EINVAL;
+
+ if (rinfo->asleep)
+ return 0;
+
+ OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
+ * var->bits_per_pixel / 8) & ~7);
- offset = ((yoffset * var->xres + xoffset) * var->bits_per_pixel) >> 6;
-
- OUTREG(CRTC_OFFSET, offset);
-
return 0;
}
@@ -2127,6 +2564,79 @@
static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg, int con, struct fb_info *info)
{
+ struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
+ unsigned int tmp;
+ u32 value = 0;
+ int rc;
+
+ switch (cmd) {
+ /*
+ * TODO: set mirror accordingly for non-Mobility chipsets with 2 CRTC's
+ */
+ case FBIO_RADEON_SET_MIRROR:
+ switch (rinfo->arch) {
+ case RADEON_M6:
+ case RADEON_M7:
+ case RADEON_M9:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = get_user(value, (__u32*)arg);
+
+ if (rc)
+ return rc;
+
+ if (value & 0x01) {
+ tmp = INREG(LVDS_GEN_CNTL);
+
+ tmp |= (LVDS_ON | LVDS_BLON);
+ } else {
+ tmp = INREG(LVDS_GEN_CNTL);
+
+ tmp &= ~(LVDS_ON | LVDS_BLON);
+ }
+
+ OUTREG(LVDS_GEN_CNTL, tmp);
+
+ if (value & 0x02) {
+ tmp = INREG(CRTC_EXT_CNTL);
+ tmp |= CRTC_CRT_ON;
+
+ mirror = 1;
+ } else {
+ tmp = INREG(CRTC_EXT_CNTL);
+ tmp &= ~CRTC_CRT_ON;
+
+ mirror = 0;
+ }
+
+ OUTREG(CRTC_EXT_CNTL, tmp);
+
+ return 0;
+
+ case FBIO_RADEON_GET_MIRROR:
+ switch (rinfo->arch) {
+ case RADEON_M6:
+ case RADEON_M7:
+ case RADEON_M9:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tmp = INREG(LVDS_GEN_CNTL);
+ if ((LVDS_ON | LVDS_BLON) & tmp)
+ value |= 0x01;
+
+ tmp = INREG(CRTC_EXT_CNTL);
+ if (CRTC_CRT_ON & tmp)
+ value |= 0x02;
+
+ return put_user(value, (__u32*)arg);
+ }
+
return -EINVAL;
}
@@ -2134,42 +2644,55 @@
static int radeonfb_switch (int con, struct fb_info *info)
{
struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
- struct display *disp;
+ struct display *disp, *old_disp;
struct fb_cmap *cmap;
int switchmode = 0;
disp = (con < 0) ? rinfo->info.disp : &fb_display[con];
+ old_disp = rinfo->currcon_display;
if (rinfo->currcon >= 0) {
cmap = &(rinfo->currcon_display->cmap);
if (cmap->len)
fb_get_cmap (cmap, 1, radeon_getcolreg, info);
}
-
- switchmode = (con != rinfo->currcon);
+ if ((old_disp == NULL) || ((disp->var.xres != old_disp->var.xres) ||
+ (disp->var.yres != old_disp->var.yres) ||
+ (disp->var.xres_virtual != old_disp->var.xres_virtual) ||
+ (disp->var.yres_virtual != old_disp->var.yres_virtual) ||
+ (disp->var.bits_per_pixel != old_disp->var.bits_per_pixel) ||
+ memcmp (&disp->var.red, &old_disp->var.red, sizeof (old_disp->var.red)) ||
+ memcmp (&disp->var.green, &old_disp->var.green, sizeof (old_disp->var.green)) ||
+ memcmp (&disp->var.blue, &old_disp->var.blue, sizeof (old_disp->var.blue)) ||
+ old_disp->var.accel_flags != disp->var.accel_flags))
+ switchmode = 1;
+
+ if (rinfo->currcon == -1)
+ switchmode = 1;
+
+try_again:
rinfo->currcon = con;
rinfo->currcon_display = disp;
disp->var.activate = FB_ACTIVATE_NOW;
if (switchmode) {
radeonfb_set_var (&disp->var, con, info);
- radeon_set_dispsw (rinfo, disp);
do_install_cmap(con, info);
- }
-
- /* XXX absurd hack for X to restore console */
- {
- OUTREGP(CRTC_EXT_CNTL, rinfo->hack_crtc_ext_cntl,
- CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS);
- OUTREG(CRTC_V_SYNC_STRT_WID, rinfo->hack_crtc_v_sync_strt_wid);
+ } else {
+ if (radeon_engine_init(rinfo) < 0) {
+ disp->var.accel_flags &= ~FB_ACCELF_TEXT;
+ switchmode = 1;
+ goto try_again;
+ }
}
+ radeon_set_dispsw (rinfo, disp);
+
return 0;
}
-
static int radeonfb_updatevar (int con, struct fb_info *info)
{
int rc;
@@ -2184,8 +2707,12 @@
{
struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
u32 val = INREG(CRTC_EXT_CNTL);
- u32 val2 = INREG(LVDS_GEN_CNTL);
+ u32 val_lvds = INREG(LVDS_GEN_CNTL);
+ u32 val_dfp = INREG(FP_GEN_CNTL);
+ if (rinfo->asleep)
+ return;
+
#ifdef CONFIG_PMAC_BACKLIGHT
if (rinfo->dviDisp_type == MT_LCD && _machine == _MACH_Pmac) {
set_backlight_enable(!blank);
@@ -2196,7 +2723,8 @@
/* reset it */
val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
CRTC_VSYNC_DIS);
- val2 &= ~(LVDS_DISPLAY_DIS);
+ val_lvds &= ~(LVDS_DISPLAY_DIS);
+ val_dfp |= FP_FPON | FP_TMDS_EN;
switch (blank) {
case VESA_NO_BLANKING:
@@ -2210,13 +2738,17 @@
case VESA_POWERDOWN:
val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS |
CRTC_HSYNC_DIS);
- val2 |= (LVDS_DISPLAY_DIS);
+ val_lvds |= (LVDS_DISPLAY_DIS);
+ val_dfp &= ~(FP_FPON | FP_TMDS_EN);
break;
}
switch (rinfo->dviDisp_type) {
case MT_LCD:
- OUTREG(LVDS_GEN_CNTL, val2);
+ OUTREG(LVDS_GEN_CNTL, val_lvds);
+ break;
+ case MT_DFP:
+ OUTREG(FP_GEN_CNTL, val_dfp);
break;
case MT_CRT:
default:
@@ -2243,7 +2775,6 @@
}
-
static int radeon_getcolreg (unsigned regno, unsigned *red, unsigned *green,
unsigned *blue, unsigned *transp,
struct fb_info *info)
@@ -2281,29 +2812,44 @@
/* default */
pindex = regno;
-
- if (rinfo->bpp == 16) {
- pindex = regno * 8;
- if (rinfo->depth == 16 && regno > 63)
- return 1;
- if (rinfo->depth == 15 && regno > 31)
- return 1;
+ if (!rinfo->asleep) {
+ u32 dac_cntl2, vclk_cntl;
+
+ vclk_cntl = INPLL(VCLK_ECP_CNTL);
+ OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
+
+ /* Make sure we are on first palette */
+ if (rinfo->hasCRTC2) {
+ dac_cntl2 = INREG(DAC_CNTL2);
+ dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
+ OUTREG(DAC_CNTL2, dac_cntl2);
+ }
- /* For 565, the green component is mixed one order below */
- if (rinfo->depth == 16) {
- OUTREG(PALETTE_INDEX, pindex>>1);
- OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) |
- (green << 8) | (rinfo->palette[regno>>1].blue));
- green = rinfo->palette[regno<<1].green;
- }
- }
+ if (rinfo->bpp == 16) {
+ pindex = regno * 8;
- if (rinfo->depth != 16 || regno < 32) {
- OUTREG(PALETTE_INDEX, pindex);
- OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue);
- }
+ if (rinfo->depth == 16 && regno > 63)
+ return 1;
+ if (rinfo->depth == 15 && regno > 31)
+ return 1;
+
+ /* For 565, the green component is mixed one order below */
+ if (rinfo->depth == 16) {
+ OUTREG8(PALETTE_INDEX, pindex>>1);
+ OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) |
+ (green << 8) | (rinfo->palette[regno>>1].blue));
+ green = rinfo->palette[regno<<1].green;
+ }
+ }
+ if (rinfo->depth != 16 || regno < 32) {
+ OUTREG8(PALETTE_INDEX, pindex);
+ OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue);
+ }
+
+ OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
+ }
if (regno < 16) {
switch (rinfo->depth) {
#ifdef FBCON_HAS_CFB16
@@ -2316,7 +2862,7 @@
regno;
break;
#endif
-#ifdef FBCON_HAS_CFB24
+#ifdef FBCON_HAS_CFB24
case 24:
rinfo->con_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | regno;
break;
@@ -2330,11 +2876,11 @@
break;
}
#endif
- }
+ }
}
- return 0;
-}
+ return 0;
+}
static void radeon_save_state (struct radeonfb_info *rinfo,
@@ -2343,6 +2889,7 @@
/* CRTC regs */
save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL);
+ save->crtc_more_cntl = INREG(CRTC_MORE_CNTL);
save->dac_cntl = INREG(DAC_CNTL);
save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP);
save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID);
@@ -2365,9 +2912,58 @@
save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL);
save->tmds_crc = INREG(TMDS_CRC);
save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL);
+ save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL);
}
+static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *regs, unsigned long freq)
+{
+ const struct {
+ int divider;
+ int bitvalue;
+ } *post_div,
+ post_divs[] = {
+ { 1, 0 },
+ { 2, 1 },
+ { 4, 2 },
+ { 8, 3 },
+ { 3, 4 },
+ { 16, 5 },
+ { 6, 6 },
+ { 12, 7 },
+ { 0, 0 },
+ };
+
+ if (freq > rinfo->pll.ppll_max)
+ freq = rinfo->pll.ppll_max;
+ if (freq*12 < rinfo->pll.ppll_min)
+ freq = rinfo->pll.ppll_min / 12;
+
+
+ for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
+ rinfo->pll_output_freq = post_div->divider * freq;
+ if (rinfo->pll_output_freq >= rinfo->pll.ppll_min &&
+ rinfo->pll_output_freq <= rinfo->pll.ppll_max)
+ break;
+ }
+
+ /* Why do we have those in rinfo at this point ? --BenH */
+ rinfo->post_div = post_div->divider;
+ rinfo->fb_div = round_div(rinfo->pll.ref_div*rinfo->pll_output_freq,
+ rinfo->pll.ref_clk);
+ regs->ppll_ref_div = rinfo->pll.ref_div;
+ regs->ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16);
+
+#ifdef CONFIG_ALL_PPC
+ /* Gross hack for iBook with M7 until I find out a proper fix */
+ if (machine_is_compatible("PowerBook4,3") && rinfo->arch == RADEON_M7)
+ regs->ppll_div_3 = 0x000600ad;
+#endif /* CONFIG_ALL_PPC */
+
+ RTRACE("post div = 0x%x\n", rinfo->post_div);
+ RTRACE("fb_div = 0x%x\n", rinfo->fb_div);
+ RTRACE("ppll_div_3 = 0x%x\n", regs->ppll_div_3);
+}
static void radeon_load_video_mode (struct radeonfb_info *rinfo,
struct fb_var_screeninfo *mode)
@@ -2377,18 +2973,24 @@
hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync;
u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5};
u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5};
- u32 dotClock = 1000000000 / mode->pixclock,
- sync, h_sync_pol, v_sync_pol;
- int freq = dotClock / 10; /* x 100 */
- int xclk_freq, vclk_freq, xclk_per_trans, xclk_per_trans_precise;
+ u32 sync, h_sync_pol, v_sync_pol, dotClock, pixClock;
+ unsigned int freq;
+#if 0
+ unsigned int xclk_freq, vclk_freq;
+ int xclk_per_trans, xclk_per_trans_precise;
int useable_precision, roff, ron;
- int min_bits, format = 0;
+ int min_bits;
+#endif
+ int format = 0;
int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid;
int primary_mon = PRIMARY_MONITOR(rinfo);
int depth = var_to_depth(mode);
+ int accel = mode->accel_flags & FB_ACCELF_TEXT;
rinfo->xres = mode->xres;
rinfo->yres = mode->yres;
+ rinfo->xres_virtual = mode->xres_virtual;
+ rinfo->yres_virtual = mode->yres_virtual;
rinfo->pixclock = mode->pixclock;
hSyncStart = mode->xres + mode->right_margin;
@@ -2398,8 +3000,18 @@
vSyncStart = mode->yres + mode->lower_margin;
vSyncEnd = vSyncStart + mode->vsync_len;
vTotal = vSyncEnd + mode->upper_margin;
-
+ pixClock = mode->pixclock;
+
if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
+ /* Force the native video mode of the LCD monitor.
+ * This is complicated, because when the hardware
+ * stretcher is used, the extra pixels are not counted
+ * in the horizontal timing parameters. So:
+ * - For the visible part of the display, we use the
+ * requested paramters.
+ * - For the invisible part of the display, we use the
+ * parameters of the native video mode.
+ */
if (rinfo->panel_xres < mode->xres)
rinfo->xres = mode->xres = rinfo->panel_xres;
if (rinfo->panel_yres < mode->yres)
@@ -2412,7 +3024,15 @@
vTotal = mode->yres + rinfo->vblank;
vSyncStart = mode->yres + rinfo->vOver_plus;
vSyncEnd = vSyncStart + rinfo->vSync_width;
+
+ /* If we know the LCD clock, we shall use it, unfortunately,
+ * we may not know it until we have proper EDID probing
+ */
+ if (rinfo->clock)
+ pixClock = 100000000 / rinfo->clock;
}
+ dotClock = 1000000000 / pixClock;
+ freq = dotClock / 10; /* x100 */
sync = mode->sync;
h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
@@ -2453,8 +3073,18 @@
newmode.crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN |
(format << 8);
+ /* Clear auto-center etc... Maybe we can actually use these
+ * later, when I implement a scaling mode that keep
+ * aspect ratio
+ */
+ newmode.crtc_more_cntl = rinfo->init_state.crtc_more_cntl;
+ newmode.crtc_more_cntl &= 0xfffffff0;
+
if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN;
+ if (mirror)
+ newmode.crtc_ext_cntl |= CRTC_CRT_ON;
+
newmode.crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN |
CRTC_INTERLACE_EN);
} else {
@@ -2477,25 +3107,44 @@
newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
(vsync_wid << 16) | (v_sync_pol << 23));
- newmode.crtc_pitch = (mode->xres >> 3);
+ /* We first calculate the engine pitch (we always calculate it as this value may
+ * be used elsewhere, like when setting us the btext engine
+ */
+ rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
+ & ~(0x3f)) >> 6;
+ if (accel)
+ /* Then, re-multiply it to get the CRTC pitch */
+ newmode.crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8);
+ else
+ newmode.crtc_pitch = (mode->xres_virtual >> 3);
+
newmode.crtc_pitch |= (newmode.crtc_pitch << 16);
+ /*
+ * It looks like recent chips have a problem with SURFACE_CNTL,
+ * setting SURF_TRANSLATION_DIS completely disables the
+ * swapper as well, so we leave it unset now.
+ */
+ newmode.surface_cntl = 0;
+
#if defined(__BIG_ENDIAN)
- newmode.surface_cntl = SURF_TRANSLATION_DIS;
+ /* Setup swapping on both apertures, though we currently
+ * only use aperture 0, enabling swapper on aperture 1
+ * won't harm
+ */
switch (mode->bits_per_pixel) {
case 16:
newmode.surface_cntl |= NONSURF_AP0_SWP_16BPP;
+ newmode.surface_cntl |= NONSURF_AP1_SWP_16BPP;
break;
case 24:
case 32:
newmode.surface_cntl |= NONSURF_AP0_SWP_32BPP;
+ newmode.surface_cntl |= NONSURF_AP1_SWP_32BPP;
break;
}
#endif
- rinfo->pitch = ((mode->xres * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
- & ~(0x3f)) / 64;
-
RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n",
newmode.crtc_h_total_disp, newmode.crtc_h_sync_strt_wid);
RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n",
@@ -2507,50 +3156,17 @@
rinfo->bpp = mode->bits_per_pixel;
rinfo->depth = depth;
- rinfo->hack_crtc_ext_cntl = newmode.crtc_ext_cntl;
- rinfo->hack_crtc_v_sync_strt_wid = newmode.crtc_v_sync_strt_wid;
+ RTRACE("pixclock = %lu\n", (unsigned long)pixClock);
+ RTRACE("freq = %lu\n", (unsigned long)freq);
+ radeon_calc_pll_regs(rinfo, &newmode, freq);
- if (freq > rinfo->pll.ppll_max)
- freq = rinfo->pll.ppll_max;
- if (freq*12 < rinfo->pll.ppll_min)
- freq = rinfo->pll.ppll_min / 12;
-
- {
- struct {
- int divider;
- int bitvalue;
- } *post_div,
- post_divs[] = {
- { 1, 0 },
- { 2, 1 },
- { 4, 2 },
- { 8, 3 },
- { 3, 4 },
- { 16, 5 },
- { 6, 6 },
- { 12, 7 },
- { 0, 0 },
- };
-
- for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
- rinfo->pll_output_freq = post_div->divider * freq;
- if (rinfo->pll_output_freq >= rinfo->pll.ppll_min &&
- rinfo->pll_output_freq <= rinfo->pll.ppll_max)
- break;
- }
-
- rinfo->post_div = post_div->divider;
- rinfo->fb_div = round_div(rinfo->pll.ref_div*rinfo->pll_output_freq,
- rinfo->pll.ref_clk);
- newmode.ppll_ref_div = rinfo->pll.ref_div;
- newmode.ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16);
- }
-
- RTRACE("post div = 0x%x\n", rinfo->post_div);
- RTRACE("fb_div = 0x%x\n", rinfo->fb_div);
- RTRACE("ppll_div_3 = 0x%x\n", newmode.ppll_div_3);
+ newmode.vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl;
+#if 0
/* DDA */
+ /* XXX: Figure out if there is really a DDA on radeons ! I think there
+ * isn't actually...
+ */
vclk_freq = round_div(rinfo->pll.ref_clk * rinfo->fb_div,
rinfo->pll.ref_div * rinfo->post_div);
xclk_freq = rinfo->pll.xclk;
@@ -2580,6 +3196,7 @@
(useable_precision << 16) |
(rinfo->ram.rloop << 20));
newmode.dda_on_off = (ron << 16) | roff;
+#endif
if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
unsigned int hRatio, vRatio;
@@ -2607,13 +3224,13 @@
newmode.fp_horz_stretch &= ~HORZ_AUTO_RATIO;
if (mode->yres != rinfo->panel_yres) {
- vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX,
- rinfo->panel_yres);
- newmode.fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) |
- (newmode.fp_vert_stretch &
- (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED)));
- newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND |
- VERT_STRETCH_ENABLE);
+ vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX,
+ rinfo->panel_yres);
+ newmode.fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) |
+ (newmode.fp_vert_stretch &
+ (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED)));
+ newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND |
+ VERT_STRETCH_ENABLE);
}
newmode.fp_vert_stretch &= ~VERT_AUTO_RATIO_EN;
@@ -2641,189 +3258,980 @@
} else {
/* DFP */
newmode.fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
- newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST |
- ICHCSEL) & ~(TMDS_PLLRST);
+ newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST | TMDS_ICHCSEL) &
+ ~(TMDS_PLLRST);
+ /* TMDS_PLL_EN bit is reversed on RV (and mobility) chips */
+ if (rinfo->arch == RADEON_R100 ||
+ rinfo->arch == RADEON_R200 ||
+ rinfo->arch == RADEON_R300 ||
+ rinfo->arch == RADEON_R350)
+ newmode.tmds_transmitter_cntl &= ~TMDS_PLL_EN;
+ else
+ newmode.tmds_transmitter_cntl |= TMDS_PLL_EN;
+
newmode.crtc_ext_cntl &= ~CRTC_CRT_ON;
}
- newmode.fp_crtc_h_total_disp = newmode.crtc_h_total_disp;
- newmode.fp_crtc_v_total_disp = newmode.crtc_v_total_disp;
- newmode.fp_h_sync_strt_wid = newmode.crtc_h_sync_strt_wid;
- newmode.fp_v_sync_strt_wid = newmode.crtc_v_sync_strt_wid;
- }
+ newmode.fp_crtc_h_total_disp = (((rinfo->hblank / 8) & 0x3ff) |
+ (((mode->xres / 8) - 1) << 16));
+ newmode.fp_crtc_v_total_disp = (rinfo->vblank & 0xffff) |
+ ((mode->yres - 1) << 16);
+ newmode.fp_h_sync_strt_wid = ((rinfo->hOver_plus & 0x1fff) |
+ (hsync_wid << 16) | (h_sync_pol << 23));
+ newmode.fp_v_sync_strt_wid = ((rinfo->vOver_plus & 0xfff) |
+ (vsync_wid << 16) | (v_sync_pol << 23));
+ }
+
+ /* do it! */
+ if (!rinfo->asleep)
+ radeon_write_mode (rinfo, &newmode);
+
+#if defined(CONFIG_BOOTX_TEXT)
+ btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres,
+ rinfo->depth, rinfo->pitch*64);
+#endif
+
+ return;
+}
+
+
+static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode)
+{
+ /* Workaround from XFree */
+ if (rinfo->arch < RADEON_R300) {
+ /* A temporal workaround for the occational blanking on certain laptop panels.
+ This appears to related to the PLL divider registers (fail to lock?).
+ It occurs even when all dividers are the same with their old settings.
+ In this case we really don't need to fiddle with PLL registers.
+ By doing this we can avoid the blanking problem with some panels.
+ */
+ if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) &&
+ (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) &
+ (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK))))
+ return;
+ }
+
+ while ((INREG(CLOCK_CNTL_INDEX) & PPLL_DIV_SEL_MASK) !=
+ PPLL_DIV_SEL_MASK) {
+ OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, 0xffff);
+ }
+
+ OUTPLLP(PPLL_CNTL, PPLL_RESET, 0xffff);
+
+ while ((INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK) !=
+ (mode->ppll_ref_div & PPLL_REF_DIV_MASK)) {
+ OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
+ }
+
+ while ((INPLL(PPLL_DIV_3) & PPLL_FB3_DIV_MASK) !=
+ (mode->ppll_div_3 & PPLL_FB3_DIV_MASK)) {
+ OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
+ }
+
+ while ((INPLL(PPLL_DIV_3) & PPLL_POST3_DIV_MASK) !=
+ (mode->ppll_div_3 & PPLL_POST3_DIV_MASK)) {
+ OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
+ }
+
+ OUTPLL(HTOTAL_CNTL, 0);
+
+ OUTPLLP(PPLL_CNTL, 0, ~PPLL_RESET);
+}
+
+static void radeon_write_mode (struct radeonfb_info *rinfo,
+ struct radeon_regs *mode)
+{
+ int i;
+ int primary_mon = PRIMARY_MONITOR(rinfo);
+
+ radeonfb_blank(VESA_POWERDOWN, (struct fb_info *)rinfo);
+
+ if (rinfo->arch == RADEON_M6) {
+ for (i=0; i<8; i++)
+ OUTREG(common_regs_m6[i].reg, common_regs_m6[i].val);
+ } else {
+ for (i=0; i<9; i++)
+ OUTREG(common_regs[i].reg, common_regs[i].val);
+ }
+
+ OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
+ OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
+ CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS);
+ OUTREG(CRTC_MORE_CNTL, mode->crtc_more_cntl);
+ OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
+ OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
+ OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
+ OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
+ OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
+ OUTREG(CRTC_OFFSET, 0);
+ OUTREG(CRTC_OFFSET_CNTL, 0);
+ OUTREG(CRTC_PITCH, mode->crtc_pitch);
+ OUTREG(SURFACE_CNTL, mode->surface_cntl);
+
+ radeon_write_pll_regs(rinfo, mode);
+
+#if 0
+ /* Those don't seem to actually exist in radeon's, despite some drivers still
+ * apparently trying to fill them, including some ATI sample codes ...
+ * Can someone confirm what's up ? --BenH.
+ */
+ OUTREG(DDA_CONFIG, mode->dda_config);
+ OUTREG(DDA_ON_OFF, mode->dda_on_off);
+#endif
+
+ if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
+ OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp);
+ OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp);
+ OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid);
+ OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid);
+ OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch);
+ OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch);
+ OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl);
+ OUTREG(TMDS_CRC, mode->tmds_crc);
+ OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl);
+
+ if (primary_mon == MT_LCD) {
+ unsigned int tmp = INREG(LVDS_GEN_CNTL);
+
+ mode->lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ mode->lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_STATE_MASK);
+
+ if ((tmp & (LVDS_ON | LVDS_BLON)) ==
+ (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) {
+ OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
+ } else {
+ if (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) {
+ udelay(1000);
+ OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
+ } else {
+ OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl |
+ LVDS_BLON);
+ udelay(1000);
+ OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
+ }
+ }
+ }
+ }
+
+ radeonfb_blank(VESA_NO_BLANKING, (struct fb_info *)rinfo);
+
+ OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl);
+
+ return;
+}
+
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+
+/* TODO: Dbl check these tables, we don't go up to full ON backlight
+ * in these, possibly because we noticed MacOS doesn't, but I'd prefer
+ * having some more official numbers from ATI
+ */
+static int backlight_conv_m6[] = {
+ 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
+ 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
+};
+static int backlight_conv_m7[] = {
+ 0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
+ 0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
+};
+
+/* We turn off the LCD completely instead of just dimming the backlight.
+ * This provides some greater power saving and the display is useless
+ * without backlight anyway.
+ */
+
+
+static int radeon_set_backlight_enable(int on, int level, void *data)
+{
+ struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
+ unsigned int lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+ int* conv_table;
+
+ /* Pardon me for that hack... maybe some day we can figure
+ * out in what direction backlight should work on a given
+ * panel ?
+ */
+ if ((rinfo->arch == RADEON_M7 || rinfo->arch == RADEON_M9)
+ && !machine_is_compatible("PowerBook4,3"))
+ conv_table = backlight_conv_m7;
+ else
+ conv_table = backlight_conv_m6;
+
+ lvds_gen_cntl |= (LVDS_BL_MOD_EN | LVDS_BLON);
+ if (on && (level > BACKLIGHT_OFF)) {
+ lvds_gen_cntl |= LVDS_DIGON;
+ if ((lvds_gen_cntl & LVDS_ON) == 0) {
+ lvds_gen_cntl &= ~LVDS_BLON;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ (void)INREG(LVDS_GEN_CNTL);
+ mdelay(10);
+ lvds_gen_cntl |= LVDS_BLON;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ }
+ lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+ lvds_gen_cntl |= (conv_table[level] <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ lvds_gen_cntl |= (LVDS_ON | LVDS_EN);
+ lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
+ } else {
+ lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+ lvds_gen_cntl |= (conv_table[0] <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ lvds_gen_cntl |= LVDS_DISPLAY_DIS;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ udelay(10);
+ lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGON);
+ }
+
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
+
+ return 0;
+}
+
+static int radeon_set_backlight_level(int level, void *data)
+{
+ return radeon_set_backlight_enable(1, level, data);
+}
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+
+#ifdef CONFIG_PMAC_PBOOK
+
+/*
+ * Radeon M6, M7 and M9 Power Management code. This code currently
+ * only supports the mobile chips in D2 mode, that is typically what
+ * is used on Apple laptops, it's based from some informations provided by ATI
+ * along with hours of tracing of MacOS drivers.
+ *
+ * New version of this code almost totally rewritten by ATI, many thanks
+ * for their support.
+ */
+
+static void OUTMC( struct radeonfb_info *rinfo, u8 indx, u32 value)
+{
+ OUTREG( MC_IND_INDEX, indx | MC_IND_INDEX__MC_IND_WR_EN);
+ OUTREG( MC_IND_DATA, value);
+}
+
+static u32 INMC(struct radeonfb_info *rinfo, u8 indx)
+{
+ OUTREG( MC_IND_INDEX, indx);
+ return INREG( MC_IND_DATA);
+}
+
+static void radeon_pm_save_regs(struct radeonfb_info *rinfo)
+{
+ rinfo->save_regs[0] = INPLL(PLL_PWRMGT_CNTL);
+ rinfo->save_regs[1] = INPLL(CLK_PWRMGT_CNTL);
+ rinfo->save_regs[2] = INPLL(MCLK_CNTL);
+ rinfo->save_regs[3] = INPLL(SCLK_CNTL);
+ rinfo->save_regs[4] = INPLL(CLK_PIN_CNTL);
+ rinfo->save_regs[5] = INPLL(VCLK_ECP_CNTL);
+ rinfo->save_regs[6] = INPLL(PIXCLKS_CNTL);
+ rinfo->save_regs[7] = INPLL(MCLK_MISC);
+ rinfo->save_regs[8] = INPLL(P2PLL_CNTL);
+
+ rinfo->save_regs[9] = INREG(DISP_MISC_CNTL);
+ rinfo->save_regs[10] = INREG(DISP_PWR_MAN);
+ rinfo->save_regs[11] = INREG(LVDS_GEN_CNTL);
+ rinfo->save_regs[12] = INREG(LVDS_PLL_CNTL);
+ rinfo->save_regs[13] = INREG(TV_DAC_CNTL);
+ rinfo->save_regs[14] = INREG(BUS_CNTL1);
+ rinfo->save_regs[15] = INREG(CRTC_OFFSET_CNTL);
+ rinfo->save_regs[16] = INREG(AGP_CNTL);
+ rinfo->save_regs[17] = (INREG(CRTC_GEN_CNTL) & 0xfdffffff) | 0x04000000;
+ rinfo->save_regs[18] = (INREG(CRTC2_GEN_CNTL) & 0xfdffffff) | 0x04000000;
+ rinfo->save_regs[19] = INREG(GPIOPAD_A);
+ rinfo->save_regs[20] = INREG(GPIOPAD_EN);
+ rinfo->save_regs[21] = INREG(GPIOPAD_MASK);
+ rinfo->save_regs[22] = INREG(ZV_LCDPAD_A);
+ rinfo->save_regs[23] = INREG(ZV_LCDPAD_EN);
+ rinfo->save_regs[24] = INREG(ZV_LCDPAD_MASK);
+ rinfo->save_regs[25] = INREG(GPIO_VGA_DDC);
+ rinfo->save_regs[26] = INREG(GPIO_DVI_DDC);
+ rinfo->save_regs[27] = INREG(GPIO_MONID);
+ rinfo->save_regs[28] = INREG(GPIO_CRT2_DDC);
+
+ rinfo->save_regs[29] = INREG(SURFACE_CNTL);
+ rinfo->save_regs[30] = INREG(MC_FB_LOCATION);
+ rinfo->save_regs[31] = INREG(DISPLAY_BASE_ADDR);
+ rinfo->save_regs[32] = INREG(MC_AGP_LOCATION);
+ rinfo->save_regs[33] = INREG(CRTC2_DISPLAY_BASE_ADDR);
+}
+
+static void radeon_pm_restore_regs(struct radeonfb_info *rinfo)
+{
+ OUTPLL(P2PLL_CNTL, rinfo->save_regs[8] & 0xFFFFFFFE); /* First */
+
+ OUTPLL(PLL_PWRMGT_CNTL, rinfo->save_regs[0]);
+ OUTPLL(CLK_PWRMGT_CNTL, rinfo->save_regs[1]);
+ OUTPLL(MCLK_CNTL, rinfo->save_regs[2]);
+ OUTPLL(SCLK_CNTL, rinfo->save_regs[3]);
+ OUTPLL(CLK_PIN_CNTL, rinfo->save_regs[4]);
+ OUTPLL(VCLK_ECP_CNTL, rinfo->save_regs[5]);
+ OUTPLL(PIXCLKS_CNTL, rinfo->save_regs[6]);
+ OUTPLL(MCLK_MISC, rinfo->save_regs[7]);
+
+ OUTREG(SURFACE_CNTL, rinfo->save_regs[29]);
+ OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]);
+ OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]);
+ OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]);
+ OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]);
+
+ OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
+ OUTREG(DISP_PWR_MAN, rinfo->save_regs[10]);
+ OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11]);
+ OUTREG(LVDS_PLL_CNTL,rinfo->save_regs[12]);
+ OUTREG(TV_DAC_CNTL, rinfo->save_regs[13]);
+ OUTREG(BUS_CNTL1, rinfo->save_regs[14]);
+ OUTREG(CRTC_OFFSET_CNTL, rinfo->save_regs[15]);
+ OUTREG(AGP_CNTL, rinfo->save_regs[16]);
+ OUTREG(CRTC_GEN_CNTL, rinfo->save_regs[17]);
+ OUTREG(CRTC2_GEN_CNTL, rinfo->save_regs[18]);
+
+ // wait VBL before that one ?
+ OUTPLL(P2PLL_CNTL, rinfo->save_regs[8]);
+
+ OUTREG(GPIOPAD_A, rinfo->save_regs[19]);
+ OUTREG(GPIOPAD_EN, rinfo->save_regs[20]);
+ OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]);
+ OUTREG(ZV_LCDPAD_A, rinfo->save_regs[22]);
+ OUTREG(ZV_LCDPAD_EN, rinfo->save_regs[23]);
+ OUTREG(ZV_LCDPAD_MASK, rinfo->save_regs[24]);
+ OUTREG(GPIO_VGA_DDC, rinfo->save_regs[25]);
+ OUTREG(GPIO_DVI_DDC, rinfo->save_regs[26]);
+ OUTREG(GPIO_MONID, rinfo->save_regs[27]);
+ OUTREG(GPIO_CRT2_DDC, rinfo->save_regs[28]);
+}
+
+static void radeon_pm_disable_iopad(struct radeonfb_info *rinfo)
+{
+ OUTREG(GPIOPAD_MASK, 0x0001ffff);
+ OUTREG(GPIOPAD_EN, 0x00000400);
+ OUTREG(GPIOPAD_A, 0x00000000);
+ OUTREG(ZV_LCDPAD_MASK, 0x00000000);
+ OUTREG(ZV_LCDPAD_EN, 0x00000000);
+ OUTREG(ZV_LCDPAD_A, 0x00000000);
+ OUTREG(GPIO_VGA_DDC, 0x00030000);
+ OUTREG(GPIO_DVI_DDC, 0x00000000);
+ OUTREG(GPIO_MONID, 0x00030000);
+ OUTREG(GPIO_CRT2_DDC, 0x00000000);
+}
+
+static void radeon_pm_program_v2clk(struct radeonfb_info *rinfo)
+{
+ /* Set v2clk to 65MHz */
+ OUTPLL(pllPIXCLKS_CNTL,
+ INPLL(pllPIXCLKS_CNTL) & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK);
+
+ OUTPLL(pllP2PLL_REF_DIV, 0x0000000c);
+ OUTPLL(pllP2PLL_CNTL, 0x0000bf00);
+ OUTPLL(pllP2PLL_DIV_0, 0x00020074 | P2PLL_DIV_0__P2PLL_ATOMIC_UPDATE_W);
+
+ OUTPLL(pllP2PLL_CNTL, INPLL(pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_SLEEP);
+ mdelay(1);
+
+ OUTPLL(pllP2PLL_CNTL, INPLL(pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_RESET);
+ mdelay( 1);
+
+ OUTPLL(pllPIXCLKS_CNTL,
+ (INPLL(pllPIXCLKS_CNTL) & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK)
+ | (0x03 << PIXCLKS_CNTL__PIX2CLK_SRC_SEL__SHIFT));
+ mdelay( 1);
+}
+
+static void radeon_pm_low_current(struct radeonfb_info *rinfo)
+{
+ u32 reg;
+
+ reg = INREG(BUS_CNTL1);
+ reg &= ~BUS_CNTL1_MOBILE_PLATFORM_SEL_MASK;
+ reg |= BUS_CNTL1_AGPCLK_VALID | (1<<BUS_CNTL1_MOBILE_PLATFORM_SEL_SHIFT);
+ OUTREG(BUS_CNTL1, reg);
+
+ reg = INPLL(PLL_PWRMGT_CNTL);
+ reg |= PLL_PWRMGT_CNTL_SPLL_TURNOFF | PLL_PWRMGT_CNTL_PPLL_TURNOFF |
+ PLL_PWRMGT_CNTL_P2PLL_TURNOFF | PLL_PWRMGT_CNTL_TVPLL_TURNOFF;
+ reg &= ~PLL_PWRMGT_CNTL_SU_MCLK_USE_BCLK;
+ reg &= ~PLL_PWRMGT_CNTL_MOBILE_SU;
+ OUTPLL(PLL_PWRMGT_CNTL, reg);
+
+ reg = INREG(TV_DAC_CNTL);
+ reg &= ~(TV_DAC_CNTL_BGADJ_MASK |TV_DAC_CNTL_DACADJ_MASK);
+ reg |=TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD |
+ TV_DAC_CNTL_BDACPD |
+ (8<<TV_DAC_CNTL_BGADJ__SHIFT) | (8<<TV_DAC_CNTL_DACADJ__SHIFT);
+ OUTREG(TV_DAC_CNTL, reg);
+
+ reg = INREG(TMDS_TRANSMITTER_CNTL);
+ reg &= ~(TMDS_PLL_EN | TMDS_PLLRST);
+ OUTREG(TMDS_TRANSMITTER_CNTL, reg);
+
+ reg = INREG(DAC_CNTL);
+ reg &= ~DAC_CMP_EN;
+ OUTREG(DAC_CNTL, reg);
+
+ reg = INREG(DAC_CNTL2);
+ reg &= ~DAC2_CMP_EN;
+ OUTREG(DAC_CNTL2, reg);
+
+ reg = INREG(TV_DAC_CNTL);
+ reg &= ~TV_DAC_CNTL_DETECT;
+ OUTREG(TV_DAC_CNTL, reg);
+}
+
+static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
+{
+
+ u32 sclk_cntl, mclk_cntl, sclk_more_cntl;
+
+ u32 pll_pwrmgt_cntl;
+ u32 clk_pwrmgt_cntl;
+ u32 clk_pin_cntl;
+ u32 vclk_ecp_cntl;
+ u32 pixclks_cntl;
+ u32 disp_mis_cntl;
+ u32 disp_pwr_man;
+
+
+ /* Force Core Clocks */
+ sclk_cntl = INPLL( pllSCLK_CNTL_M6);
+ sclk_cntl |= SCLK_CNTL_M6__IDCT_MAX_DYN_STOP_LAT|
+ SCLK_CNTL_M6__VIP_MAX_DYN_STOP_LAT|
+ SCLK_CNTL_M6__RE_MAX_DYN_STOP_LAT|
+ SCLK_CNTL_M6__PB_MAX_DYN_STOP_LAT|
+ SCLK_CNTL_M6__TAM_MAX_DYN_STOP_LAT|
+ SCLK_CNTL_M6__TDM_MAX_DYN_STOP_LAT|
+ SCLK_CNTL_M6__RB_MAX_DYN_STOP_LAT|
+
+ SCLK_CNTL_M6__FORCE_DISP2|
+ SCLK_CNTL_M6__FORCE_CP|
+ SCLK_CNTL_M6__FORCE_HDP|
+ SCLK_CNTL_M6__FORCE_DISP1|
+ SCLK_CNTL_M6__FORCE_TOP|
+ SCLK_CNTL_M6__FORCE_E2|
+ SCLK_CNTL_M6__FORCE_SE|
+ SCLK_CNTL_M6__FORCE_IDCT|
+ SCLK_CNTL_M6__FORCE_VIP|
+
+ SCLK_CNTL_M6__FORCE_RE|
+ SCLK_CNTL_M6__FORCE_PB|
+ SCLK_CNTL_M6__FORCE_TAM|
+ SCLK_CNTL_M6__FORCE_TDM|
+ SCLK_CNTL_M6__FORCE_RB|
+ SCLK_CNTL_M6__FORCE_TV_SCLK|
+ SCLK_CNTL_M6__FORCE_SUBPIC|
+ SCLK_CNTL_M6__FORCE_OV0;
+
+ OUTPLL( pllSCLK_CNTL_M6, sclk_cntl);
+
+ sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL);
+ sclk_more_cntl |= SCLK_MORE_CNTL__FORCE_DISPREGS |
+ SCLK_MORE_CNTL__FORCE_MC_GUI |
+ SCLK_MORE_CNTL__FORCE_MC_HOST;
+
+ OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl);
+
+
+ mclk_cntl = INPLL( pllMCLK_CNTL_M6);
+ mclk_cntl &= ~( MCLK_CNTL_M6__FORCE_MCLKA |
+ MCLK_CNTL_M6__FORCE_MCLKB |
+ MCLK_CNTL_M6__FORCE_YCLKA |
+ MCLK_CNTL_M6__FORCE_YCLKB |
+ MCLK_CNTL_M6__FORCE_MC
+ );
+ OUTPLL( pllMCLK_CNTL_M6, mclk_cntl);
+
+ /* Force Display clocks */
+ vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL);
+ vclk_ecp_cntl &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
+ vclk_ecp_cntl |= VCLK_ECP_CNTL__ECP_FORCE_ON;
+ OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl);
+
+
+ pixclks_cntl = INPLL( pllPIXCLKS_CNTL);
+ pixclks_cntl &= ~( PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb |
+ PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb |
+ PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb);
+
+ OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl);
+
+
+
+ /* Enable System power management */
+ pll_pwrmgt_cntl = INPLL( pllPLL_PWRMGT_CNTL);
+
+ pll_pwrmgt_cntl |= PLL_PWRMGT_CNTL__SPLL_TURNOFF |
+ PLL_PWRMGT_CNTL__MPLL_TURNOFF|
+ PLL_PWRMGT_CNTL__PPLL_TURNOFF|
+ PLL_PWRMGT_CNTL__P2PLL_TURNOFF|
+ PLL_PWRMGT_CNTL__TVPLL_TURNOFF;
+
+ OUTPLL( pllPLL_PWRMGT_CNTL, pll_pwrmgt_cntl);
+
+ clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL_M6);
+
+ clk_pwrmgt_cntl &= ~( CLK_PWRMGT_CNTL_M6__MPLL_PWRMGT_OFF|
+ CLK_PWRMGT_CNTL_M6__SPLL_PWRMGT_OFF|
+ CLK_PWRMGT_CNTL_M6__PPLL_PWRMGT_OFF|
+ CLK_PWRMGT_CNTL_M6__P2PLL_PWRMGT_OFF|
+ CLK_PWRMGT_CNTL_M6__MCLK_TURNOFF|
+ CLK_PWRMGT_CNTL_M6__SCLK_TURNOFF|
+ CLK_PWRMGT_CNTL_M6__PCLK_TURNOFF|
+ CLK_PWRMGT_CNTL_M6__P2CLK_TURNOFF|
+ CLK_PWRMGT_CNTL_M6__TVPLL_PWRMGT_OFF|
+ CLK_PWRMGT_CNTL_M6__GLOBAL_PMAN_EN|
+ CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE|
+ CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT_MASK|
+ CLK_PWRMGT_CNTL_M6__CG_NO1_DEBUG_MASK
+ );
+
+ clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL_M6__GLOBAL_PMAN_EN | CLK_PWRMGT_CNTL_M6__DISP_PM;
+
+ OUTPLL( pllCLK_PWRMGT_CNTL_M6, clk_pwrmgt_cntl);
+
+ clk_pin_cntl = INPLL( pllCLK_PIN_CNTL);
+
+ clk_pin_cntl &= ~CLK_PIN_CNTL__ACCESS_REGS_IN_SUSPEND;
+ OUTPLL( pllMCLK_MISC, INPLL( pllMCLK_MISC) | MCLK_MISC__EN_MCLK_TRISTATE_IN_SUSPEND);
+
+ /* AGP PLL control */
+ OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | BUS_CNTL1__AGPCLK_VALID);
+
+ OUTREG(BUS_CNTL1,
+ (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
+ | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT)); // 440BX
+ OUTREG(CRTC_OFFSET_CNTL, (INREG(CRTC_OFFSET_CNTL) & ~CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN));
+
+ clk_pin_cntl &= ~CLK_PIN_CNTL__CG_CLK_TO_OUTPIN;
+ clk_pin_cntl |= CLK_PIN_CNTL__XTALIN_ALWAYS_ONb;
+ OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl);
+
+ /* Solano2M */
+ OUTREG(AGP_CNTL,
+ (INREG(AGP_CNTL) & ~(AGP_CNTL__MAX_IDLE_CLK_MASK))
+ | (0x20<<AGP_CNTL__MAX_IDLE_CLK__SHIFT));
+
+ /* ACPI mode */
+ OUTPLL( pllPLL_PWRMGT_CNTL, INPLL( pllPLL_PWRMGT_CNTL) & ~PLL_PWRMGT_CNTL__PM_MODE_SEL);
+
+
+ disp_mis_cntl = INREG(DISP_MISC_CNTL);
+
+ disp_mis_cntl &= ~( DISP_MISC_CNTL__SOFT_RESET_GRPH_PP |
+ DISP_MISC_CNTL__SOFT_RESET_SUBPIC_PP |
+ DISP_MISC_CNTL__SOFT_RESET_OV0_PP |
+ DISP_MISC_CNTL__SOFT_RESET_GRPH_SCLK|
+ DISP_MISC_CNTL__SOFT_RESET_SUBPIC_SCLK|
+ DISP_MISC_CNTL__SOFT_RESET_OV0_SCLK|
+ DISP_MISC_CNTL__SOFT_RESET_GRPH2_PP|
+ DISP_MISC_CNTL__SOFT_RESET_GRPH2_SCLK|
+ DISP_MISC_CNTL__SOFT_RESET_LVDS|
+ DISP_MISC_CNTL__SOFT_RESET_TMDS|
+ DISP_MISC_CNTL__SOFT_RESET_DIG_TMDS|
+ DISP_MISC_CNTL__SOFT_RESET_TV);
+
+ OUTREG(DISP_MISC_CNTL, disp_mis_cntl);
+
+ disp_pwr_man = INREG(DISP_PWR_MAN);
+
+ disp_pwr_man &= ~( DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN |
+ DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN |
+ DISP_PWR_MAN__DISP_PWR_MAN_DPMS_MASK|
+ DISP_PWR_MAN__DISP_D3_RST|
+ DISP_PWR_MAN__DISP_D3_REG_RST
+ );
+
+ disp_pwr_man |= DISP_PWR_MAN__DISP_D3_GRPH_RST|
+ DISP_PWR_MAN__DISP_D3_SUBPIC_RST|
+ DISP_PWR_MAN__DISP_D3_OV0_RST|
+ DISP_PWR_MAN__DISP_D1D2_GRPH_RST|
+ DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST|
+ DISP_PWR_MAN__DISP_D1D2_OV0_RST|
+ DISP_PWR_MAN__DIG_TMDS_ENABLE_RST|
+ DISP_PWR_MAN__TV_ENABLE_RST|
+// DISP_PWR_MAN__AUTO_PWRUP_EN|
+ 0;
+
+ OUTREG(DISP_PWR_MAN, disp_pwr_man);
+
+ clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL_M6);
+ pll_pwrmgt_cntl = INPLL( pllPLL_PWRMGT_CNTL) ;
+ clk_pin_cntl = INPLL( pllCLK_PIN_CNTL);
+ disp_pwr_man = INREG(DISP_PWR_MAN);
+
+
+ /* D2 */
+ clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL_M6__DISP_PM;
+ pll_pwrmgt_cntl |= PLL_PWRMGT_CNTL__MOBILE_SU | PLL_PWRMGT_CNTL__SU_SCLK_USE_BCLK;
+ clk_pin_cntl |= CLK_PIN_CNTL__XTALIN_ALWAYS_ONb;
+ disp_pwr_man &= ~(DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN_MASK | DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN_MASK);
+
+
+ OUTPLL( pllCLK_PWRMGT_CNTL_M6, clk_pwrmgt_cntl);
+ OUTPLL( pllPLL_PWRMGT_CNTL, pll_pwrmgt_cntl);
+ OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl);
+ OUTREG(DISP_PWR_MAN, disp_pwr_man);
+
+ /* disable display request & disable display */
+ OUTREG( CRTC_GEN_CNTL, (INREG( CRTC_GEN_CNTL) & ~CRTC_GEN_CNTL__CRTC_EN) | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B);
+ OUTREG( CRTC2_GEN_CNTL, (INREG( CRTC2_GEN_CNTL) & ~CRTC2_GEN_CNTL__CRTC2_EN) | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B);
+
+ mdelay(17);
+
+}
+
+static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
+{
+
+ u32 sclk_cntl;
+ u32 mclk_cntl;
+ u32 sclk_more_cntl;
+
+ u32 vclk_ecp_cntl;
+ u32 pixclks_cntl;
+
+ /* Mobility chips only */
+ if ((rinfo->arch != RADEON_M6) && (rinfo->arch != RADEON_M7) && (rinfo->arch != RADEON_M9))
+ return;
+
+ /* Force Core Clocks */
+ sclk_cntl = INPLL( pllSCLK_CNTL_M6);
+ sclk_cntl |= SCLK_CNTL_M6__FORCE_CP|
+ SCLK_CNTL_M6__FORCE_HDP|
+ SCLK_CNTL_M6__FORCE_DISP1|
+ SCLK_CNTL_M6__FORCE_DISP2|
+ SCLK_CNTL_M6__FORCE_TOP|
+ SCLK_CNTL_M6__FORCE_E2|
+ SCLK_CNTL_M6__FORCE_SE|
+ SCLK_CNTL_M6__FORCE_IDCT|
+ SCLK_CNTL_M6__FORCE_VIP|
+ SCLK_CNTL_M6__FORCE_RE|
+ SCLK_CNTL_M6__FORCE_PB|
+ SCLK_CNTL_M6__FORCE_TAM|
+ SCLK_CNTL_M6__FORCE_TDM|
+ SCLK_CNTL_M6__FORCE_RB|
+ SCLK_CNTL_M6__FORCE_TV_SCLK|
+ SCLK_CNTL_M6__FORCE_SUBPIC|
+ SCLK_CNTL_M6__FORCE_OV0;
+ OUTPLL( pllSCLK_CNTL_M6, sclk_cntl);
+
+
+
+ sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL);
+ sclk_more_cntl |= SCLK_MORE_CNTL__FORCE_DISPREGS|
+ SCLK_MORE_CNTL__FORCE_MC_GUI|
+ SCLK_MORE_CNTL__FORCE_MC_HOST;
+ OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl);
+
+ /* Force Display clocks */
+ vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL);
+ vclk_ecp_cntl &= ~( VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
+ VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
+
+ OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl);
+
+ pixclks_cntl = INPLL( pllPIXCLKS_CNTL);
+ pixclks_cntl &= ~( PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb |
+ PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb |
+ PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb);
+
+ OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl);
+
+ /* Force Memory Clocks */
+ mclk_cntl = INPLL( pllMCLK_CNTL_M6);
+ mclk_cntl |= MCLK_CNTL_M6__FORCE_MCLKA|
+ MCLK_CNTL_M6__FORCE_MCLKB|
+ MCLK_CNTL_M6__FORCE_YCLKA|
+ MCLK_CNTL_M6__FORCE_YCLKB;
+
+ OUTPLL( pllMCLK_CNTL_M6, mclk_cntl);
+}
+
+static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo)
+{
+ u32 clk_pwrmgt_cntl;
+ u32 sclk_cntl;
+ u32 sclk_more_cntl;
+ u32 clk_pin_cntl;
+ u32 pixclks_cntl;
+ u32 vclk_ecp_cntl;
+ u32 mclk_cntl;
+ u32 mclk_misc;
+
+ /* Mobility chips only */
+ if ((rinfo->arch != RADEON_M6) && (rinfo->arch != RADEON_M7) && (rinfo->arch != RADEON_M9))
+ return;
+
+ /* Set Latencies */
+ clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL_M6);
+
+ clk_pwrmgt_cntl &= ~( CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE_MASK|
+ CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT_MASK|
+ CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT_MASK|
+ CLK_PWRMGT_CNTL_M6__DYN_STOP_MODE_MASK);
+ /* Mode 1 */
+ clk_pwrmgt_cntl = CLK_PWRMGT_CNTL_M6__MC_CH_MODE|
+ CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE |
+ (1<<CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT__SHIFT) |
+ (0<<CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT__SHIFT)|
+ (0<<CLK_PWRMGT_CNTL_M6__DYN_STOP_MODE__SHIFT);
+
+ OUTPLL( pllCLK_PWRMGT_CNTL_M6, clk_pwrmgt_cntl);
+
+
+ clk_pin_cntl = INPLL( pllCLK_PIN_CNTL);
+ clk_pin_cntl |= CLK_PIN_CNTL__SCLK_DYN_START_CNTL;
+
+ OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl);
+
+ /* Enable Dyanmic mode for SCLK */
+
+ sclk_cntl = INPLL( pllSCLK_CNTL_M6);
+ sclk_cntl &= SCLK_CNTL_M6__SCLK_SRC_SEL_MASK;
+ sclk_cntl |= SCLK_CNTL_M6__FORCE_VIP;
+
+ OUTPLL( pllSCLK_CNTL_M6, sclk_cntl);
+
+
+ sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL);
+ sclk_more_cntl &= ~(SCLK_MORE_CNTL__FORCE_DISPREGS);
+
+ OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl);
- /* do it! */
- radeon_write_mode (rinfo, &newmode);
+
+ /* Enable Dynamic mode for PIXCLK & PIX2CLK */
-#if defined(CONFIG_BOOTX_TEXT)
- btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres,
- rinfo->depth, rinfo->pitch*64);
-#endif
+ pixclks_cntl = INPLL( pllPIXCLKS_CNTL);
+
+ pixclks_cntl|= PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb |
+ PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
+ PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb;
+
+ OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl);
+
+
+ vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL);
+
+ vclk_ecp_cntl|= VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
+ VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb;
- return;
+ OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl);
+
+
+ /* Enable Dynamic mode for MCLK */
+ mclk_cntl = INPLL( pllMCLK_CNTL_M6);
+ mclk_cntl &= ~( MCLK_CNTL_M6__FORCE_MCLKA |
+ MCLK_CNTL_M6__FORCE_MCLKB |
+ MCLK_CNTL_M6__FORCE_YCLKA |
+ MCLK_CNTL_M6__FORCE_YCLKB );
+ OUTPLL( pllMCLK_CNTL_M6, mclk_cntl);
+
+ mclk_misc = INPLL(pllMCLK_MISC);
+ mclk_misc |= MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT|
+ MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT|
+ MCLK_MISC__MC_MCLK_DYN_ENABLE|
+ MCLK_MISC__IO_MCLK_DYN_ENABLE;
+
+ OUTPLL(pllMCLK_MISC, mclk_misc);
}
-static void radeon_write_mode (struct radeonfb_info *rinfo,
- struct radeon_regs *mode)
+static void radeon_pm_yclk_mclk_sync(struct radeonfb_info *rinfo)
{
- int i;
- int primary_mon = PRIMARY_MONITOR(rinfo);
-
- /* blank screen */
- OUTREGP(CRTC_EXT_CNTL, CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS,
- ~(CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS));
+ u32 mc_chp_io_cntl_a1, mc_chp_io_cntl_b1;
- for (i=0; i<9; i++)
- OUTREG(common_regs[i].reg, common_regs[i].val);
+ mc_chp_io_cntl_a1 = INMC( rinfo, ixMC_CHP_IO_CNTL_A1) & ~MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA_MASK;
+ mc_chp_io_cntl_b1 = INMC( rinfo, ixMC_CHP_IO_CNTL_B1) & ~MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB_MASK;
- OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
- OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
- CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS);
- OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
- OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
- OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
- OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
- OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
- OUTREG(CRTC_OFFSET, 0);
- OUTREG(CRTC_OFFSET_CNTL, 0);
- OUTREG(CRTC_PITCH, mode->crtc_pitch);
+ OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1 | (1<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT));
+ OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1 | (1<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT));
-#if defined(__BIG_ENDIAN)
- OUTREG(SURFACE_CNTL, mode->surface_cntl);
+ /* Wassup ? This doesn't seem to be defined, let's hope we are ok this way --BenH */
+#ifdef MCLK_YCLK_SYNC_ENABLE
+ mc_chp_io_cntl_a1 |= (2<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT);
+ mc_chp_io_cntl_b1 |= (2<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT);
#endif
- while ((INREG(CLOCK_CNTL_INDEX) & PPLL_DIV_SEL_MASK) !=
- PPLL_DIV_SEL_MASK) {
- OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, 0xffff);
- }
+ OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1);
+ OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1);
- OUTPLLP(PPLL_CNTL, PPLL_RESET, 0xffff);
+ mdelay( 1);
+}
- while ((INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK) !=
- (mode->ppll_ref_div & PPLL_REF_DIV_MASK)) {
- OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
- }
+static void radeon_pm_program_mode_reg(struct radeonfb_info *rinfo, u16 value, u8 delay_required)
+{
+ u32 mem_sdram_mode;
- while ((INPLL(PPLL_DIV_3) & PPLL_FB3_DIV_MASK) !=
- (mode->ppll_div_3 & PPLL_FB3_DIV_MASK)) {
- OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
- }
+ mem_sdram_mode = INREG( MEM_SDRAM_MODE_REG);
- while ((INPLL(PPLL_DIV_3) & PPLL_POST3_DIV_MASK) !=
- (mode->ppll_div_3 & PPLL_POST3_DIV_MASK)) {
- OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
- }
+ mem_sdram_mode &= ~MEM_SDRAM_MODE_REG__MEM_MODE_REG_MASK;
+ mem_sdram_mode |= (value<<MEM_SDRAM_MODE_REG__MEM_MODE_REG__SHIFT) | MEM_SDRAM_MODE_REG__MEM_CFG_TYPE;
+ OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
- OUTPLL(HTOTAL_CNTL, 0);
+ mem_sdram_mode |= MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET;
+ OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
- OUTPLLP(PPLL_CNTL, 0, ~PPLL_RESET);
+ mem_sdram_mode &= ~MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET;
+ OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
- OUTREG(DDA_CONFIG, mode->dda_config);
- OUTREG(DDA_ON_OFF, mode->dda_on_off);
+ if (delay_required == 1)
+ while( (INREG( MC_STATUS) & (MC_STATUS__MEM_PWRUP_COMPL_A | MC_STATUS__MEM_PWRUP_COMPL_B) ) == 0 )
+ { };
+}
- if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
- OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp);
- OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp);
- OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid);
- OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid);
- OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch);
- OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch);
- OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl);
- OUTREG(TMDS_CRC, mode->tmds_crc);
- OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl);
- if (primary_mon == MT_LCD) {
- unsigned int tmp = INREG(LVDS_GEN_CNTL);
+static void radeon_pm_enable_dll(struct radeonfb_info *rinfo)
+{
+#define DLL_RESET_DELAY 5
+#define DLL_SLEEP_DELAY 1
- mode->lvds_gen_cntl &= ~LVDS_STATE_MASK;
- mode->lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_STATE_MASK);
+ u32 DLL_CKO_Value = INPLL(pllMDLL_CKO) | MDLL_CKO__MCKOA_SLEEP | MDLL_CKO__MCKOA_RESET;
+ u32 DLL_CKA_Value = INPLL(pllMDLL_RDCKA) | MDLL_RDCKA__MRDCKA0_SLEEP | MDLL_RDCKA__MRDCKA1_SLEEP | MDLL_RDCKA__MRDCKA0_RESET | MDLL_RDCKA__MRDCKA1_RESET;
+ u32 DLL_CKB_Value = INPLL(pllMDLL_RDCKB) | MDLL_RDCKB__MRDCKB0_SLEEP | MDLL_RDCKB__MRDCKB1_SLEEP | MDLL_RDCKB__MRDCKB0_RESET | MDLL_RDCKB__MRDCKB1_RESET;
- if ((tmp & (LVDS_ON | LVDS_BLON)) ==
- (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) {
- OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
- } else {
- if (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) {
- udelay(1000);
- OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
- } else {
- OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl |
- LVDS_BLON);
- udelay(1000);
- OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
- }
- }
- }
- }
+ /* Setting up the DLL range for write */
+ OUTPLL(pllMDLL_CKO, DLL_CKO_Value);
+ OUTPLL(pllMDLL_RDCKA, DLL_CKA_Value);
+ OUTPLL(pllMDLL_RDCKB, DLL_CKB_Value);
- /* unblank screen */
- OUTREG8(CRTC_EXT_CNTL + 1, 0);
+ mdelay( DLL_RESET_DELAY);
- return;
-}
+ /* Channel A */
+ /* Power Up */
+ DLL_CKO_Value &= ~(MDLL_CKO__MCKOA_SLEEP );
+ OUTPLL(pllMDLL_CKO, DLL_CKO_Value);
+ mdelay( DLL_SLEEP_DELAY);
+
+ DLL_CKO_Value &= ~(MDLL_CKO__MCKOA_RESET );
+ OUTPLL(pllMDLL_CKO, DLL_CKO_Value);
+ mdelay( DLL_RESET_DELAY);
+
+ /* Power Up */
+ DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA0_SLEEP );
+ OUTPLL(pllMDLL_RDCKA, DLL_CKA_Value);
+ mdelay( DLL_SLEEP_DELAY);
+
+ DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA0_RESET );
+ OUTPLL(pllMDLL_RDCKA, DLL_CKA_Value);
+ mdelay( DLL_RESET_DELAY);
+
+ /* Power Up */
+ DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA1_SLEEP);
+ OUTPLL(pllMDLL_RDCKA, DLL_CKA_Value);
+ mdelay( DLL_SLEEP_DELAY);
+
+ DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA1_RESET);
+ OUTPLL(pllMDLL_RDCKA, DLL_CKA_Value);
+ mdelay( DLL_RESET_DELAY);
+
+
+ /* Channel B */
+
+ /* Power Up */
+ DLL_CKO_Value &= ~(MDLL_CKO__MCKOB_SLEEP );
+ OUTPLL(pllMDLL_CKO, DLL_CKO_Value);
+ mdelay( DLL_SLEEP_DELAY);
+
+ DLL_CKO_Value &= ~(MDLL_CKO__MCKOB_RESET );
+ OUTPLL(pllMDLL_CKO, DLL_CKO_Value);
+ mdelay( DLL_RESET_DELAY);
-#ifdef CONFIG_PMAC_BACKLIGHT
+ /* Power Up */
+ DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB0_SLEEP);
+ OUTPLL(pllMDLL_RDCKB, DLL_CKB_Value);
+ mdelay( DLL_SLEEP_DELAY);
-static int backlight_conv[] = {
- 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
- 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
+ DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB0_RESET);
+ OUTPLL(pllMDLL_RDCKB, DLL_CKB_Value);
+ mdelay( DLL_RESET_DELAY);
-#define BACKLIGHT_LVDS_OFF
-#undef BACKLIGHT_DAC_OFF
+ /* Power Up */
+ DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB1_SLEEP);
+ OUTPLL(pllMDLL_RDCKB, DLL_CKB_Value);
+ mdelay( DLL_SLEEP_DELAY);
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides some greater power saving and the display is useless
- * without backlight anyway.
- */
+ DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB1_RESET);
+ OUTPLL(pllMDLL_RDCKB, DLL_CKB_Value);
+ mdelay( DLL_RESET_DELAY);
-static int radeon_set_backlight_enable(int on, int level, void *data)
+#undef DLL_RESET_DELAY
+#undef DLL_SLEEP_DELAY
+}
+
+static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
{
- struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
- unsigned int lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+ u32 crtcGenCntl, crtcGenCntl2, memRefreshCntl, crtc_more_cntl, fp_gen_cntl, fp2_gen_cntl;
+
+ crtcGenCntl = INREG( CRTC_GEN_CNTL);
+ crtcGenCntl2 = INREG( CRTC2_GEN_CNTL);
- lvds_gen_cntl |= (LVDS_BL_MOD_EN | LVDS_BLON);
- if (on && (level > BACKLIGHT_OFF)) {
- lvds_gen_cntl |= LVDS_DIGON;
- if ((lvds_gen_cntl & LVDS_ON) == 0) {
- lvds_gen_cntl &= ~LVDS_BLON;
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- (void)INREG(LVDS_GEN_CNTL);
- mdelay(10);
- lvds_gen_cntl |= LVDS_BLON;
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- }
- lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
- lvds_gen_cntl |= (backlight_conv[level] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- lvds_gen_cntl |= (LVDS_ON | LVDS_EN);
- lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
- } else {
- lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
- lvds_gen_cntl |= (backlight_conv[0] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- lvds_gen_cntl |= LVDS_DISPLAY_DIS;
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- udelay(10);
- lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGON);
- }
+ memRefreshCntl = INREG( MEM_REFRESH_CNTL);
+ crtc_more_cntl = INREG( CRTC_MORE_CNTL);
+ fp_gen_cntl = INREG( FP_GEN_CNTL);
+ fp2_gen_cntl = INREG( FP2_GEN_CNTL);
+
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
- rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
+ OUTREG( CRTC_MORE_CNTL, 0);
+ OUTREG( FP_GEN_CNTL, 0);
+ OUTREG( FP2_GEN_CNTL, 0);
+
+ OUTREG( CRTC_GEN_CNTL, (crtcGenCntl | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B) );
+ OUTREG( CRTC2_GEN_CNTL, (crtcGenCntl2 | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B) );
+
+ /* Disable refresh */
+ OUTREG( MEM_REFRESH_CNTL, memRefreshCntl | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+
+ /* Reset memory */
+ OUTREG( MEM_SDRAM_MODE_REG,
+ INREG( MEM_SDRAM_MODE_REG) & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); // Init Not Complete
- return 0;
-}
+ /* DLL */
+ radeon_pm_enable_dll(rinfo);
-static int radeon_set_backlight_level(int level, void *data)
-{
- return radeon_set_backlight_enable(1, level, data);
+ // MLCK /YCLK sync
+ radeon_pm_yclk_mclk_sync(rinfo);
+
+ if ((rinfo->arch == RADEON_M6) || (rinfo->arch == RADEON_M7) || (rinfo->arch == RADEON_M9)) {
+ radeon_pm_program_mode_reg(rinfo, 0x2000, 1);
+ radeon_pm_program_mode_reg(rinfo, 0x2001, 1);
+ radeon_pm_program_mode_reg(rinfo, 0x2002, 1);
+ radeon_pm_program_mode_reg(rinfo, 0x0132, 1);
+ radeon_pm_program_mode_reg(rinfo, 0x0032, 1);
+ }
+
+ OUTREG( MEM_SDRAM_MODE_REG,
+ INREG( MEM_SDRAM_MODE_REG) | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); // Init Complete
+
+ OUTREG( MEM_REFRESH_CNTL, memRefreshCntl);
+
+ OUTREG( CRTC_GEN_CNTL, crtcGenCntl);
+ OUTREG( CRTC2_GEN_CNTL, crtcGenCntl2);
+ OUTREG( FP_GEN_CNTL, fp_gen_cntl);
+ OUTREG( FP2_GEN_CNTL, fp2_gen_cntl);
+
+ OUTREG( CRTC_MORE_CNTL, crtc_more_cntl);
+
+ mdelay( 15);
}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef CONFIG_PMAC_PBOOK
static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
{
u16 pwr_cmd;
@@ -2836,28 +4244,58 @@
* including PCI config registers, clocks, AGP conf, ...)
*/
if (suspend) {
- /* Make sure CRTC2 is reset. Remove that the day
- * we decide to actually use CRTC2 and replace it with
- * real code for disabling the CRTC2 output during sleep.
+ /* Disable dynamic power management of clocks for the
+ * duration of the suspend/resume process
+ */
+ radeon_pm_disable_dynamic_mode(rinfo);
+ /* Save some registers */
+ radeon_pm_save_regs(rinfo);
+
+ /* Prepare mobility chips for suspend
*/
+ if (rinfo->arch == RADEON_M6 || rinfo->arch == RADEON_M7 || rinfo->arch == RADEON_M9) {
+ /* Program V2CLK */
+ radeon_pm_program_v2clk(rinfo);
+
+ /* Disable IO PADs */
+ radeon_pm_disable_iopad(rinfo);
+
+ /* Set low current */
+ radeon_pm_low_current(rinfo);
- pci_read_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
- &pwr_cmd);
+ /* Prepare chip for power management */
+ radeon_pm_setup_for_suspend(rinfo);
+
+ /* Reset the MDLL */
+ OUTPLL( pllMDLL_CKO, INPLL( pllMDLL_CKO) | MDLL_CKO__MCKOA_RESET | MDLL_CKO__MCKOB_RESET);
+ }
- /* Switch PCI power managment to D2 */
- pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
- (pwr_cmd & ~PCI_PM_CTRL_STATE_MASK)
- | 2);
- pci_read_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
- &pwr_cmd);
+ /* Switch PCI power managment to D2. */
+ for (;;) {
+ pci_read_config_word(
+ rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
+ &pwr_cmd);
+ if (pwr_cmd & 2)
+ break;
+ pci_write_config_word(
+ rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
+ (pwr_cmd & ~PCI_PM_CTRL_STATE_MASK) | 2);
+ mdelay(500);
+ }
} else {
/* Switch back PCI powermanagment to D0 */
- mdelay(100);
+ mdelay(200);
pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0);
- mdelay(100);
- pci_read_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
- &pwr_cmd);
- mdelay(100);
+ mdelay(500);
+
+ /* Reset the SDRAM controller */
+ if (rinfo->arch == RADEON_M6 || rinfo->arch == RADEON_M7 || rinfo->arch == RADEON_M9)
+ radeon_pm_full_reset_sdram(rinfo);
+
+ /* Restore some registers */
+ radeon_pm_restore_regs(rinfo);
+ radeon_pm_enable_dynamic_mode(rinfo);
+ mdelay(10);
}
}
@@ -2866,19 +4304,21 @@
* and restore it when we wake up again.
*/
-int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when)
+static int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when)
{
struct radeonfb_info *rinfo;
for (rinfo = board_list; rinfo != NULL; rinfo = rinfo->next) {
struct fb_fix_screeninfo fix;
int nb;
+ struct display *disp;
- switch (rinfo->chipset) {
- case PCI_DEVICE_ID_RADEON_LW:
- case PCI_DEVICE_ID_RADEON_LY:
- case PCI_DEVICE_ID_RADEON_LZ:
- case PCI_DEVICE_ID_RADEON_PM:
+ disp = (rinfo->currcon < 0) ? rinfo->info.disp : &fb_display[rinfo->currcon];
+
+ switch (rinfo->arch) {
+ case RADEON_M6:
+ case RADEON_M7:
+ case RADEON_M9:
break;
default:
return PBOOK_SLEEP_REFUSE;
@@ -2888,72 +4328,45 @@
nb = fb_display[fg_console].var.yres * fix.line_length;
switch (when) {
- case PBOOK_SLEEP_REQUEST:
-#if 0
- rinfo->save_framebuffer = vmalloc(nb);
- if (rinfo->save_framebuffer == NULL)
- return PBOOK_SLEEP_REFUSE;
-#endif
- break;
- case PBOOK_SLEEP_REJECT:
-#if 0
- if (rinfo->save_framebuffer) {
- vfree(rinfo->save_framebuffer);
- rinfo->save_framebuffer = 0;
- }
-#endif
- break;
case PBOOK_SLEEP_NOW:
- radeon_engine_idle();
- radeon_engine_reset();
- radeon_engine_idle();
+ acquire_console_sem();
+ disp->dispsw = &fbcon_dummy;
-#if 0
- /* Backup framebuffer content */
- if (rinfo->save_framebuffer)
- memcpy_fromio(rinfo->save_framebuffer,
- (void *)rinfo->fb_base,
- nb);
-#endif
+ if (!noaccel) {
+ /* Make sure engine is idle and reset */
+ radeon_engine_idle();
+ radeon_engine_reset();
+ radeon_engine_idle();
+ }
/* Blank display and LCD */
radeonfb_blank(VESA_POWERDOWN+1,
(struct fb_info *)rinfo);
/* Sleep */
+ rinfo->asleep = 1;
radeon_set_suspend(rinfo, 1);
-
+ release_console_sem();
+
break;
case PBOOK_WAKE:
- /* Wakeup */
+ acquire_console_sem();
+ /* Wakeup chip*/
radeon_set_suspend(rinfo, 0);
- radeon_engine_reset();
- if (!noaccel) {
+ /* Re-set mode */
+ rinfo->asleep = 0;
+ radeon_load_video_mode(rinfo, &disp->var);
+ if ((disp->var.accel_flags & FB_ACCELF_TEXT) && !noaccel)
radeon_engine_init(rinfo);
- radeon_engine_reset();
- }
-
-#if 0
- /* Restore framebuffer content */
- if (rinfo->save_framebuffer) {
- memcpy_toio((void *)rinfo->fb_base,
- rinfo->save_framebuffer,
- nb);
- vfree(rinfo->save_framebuffer);
- rinfo->save_framebuffer = 0;
- }
-#endif
-
- if (rinfo->currcon_display) {
- radeonfb_set_var(&rinfo->currcon_display->var, rinfo->currcon,
- (struct fb_info *) rinfo);
- radeon_set_dispsw(rinfo, rinfo->currcon_display);
- do_install_cmap(rinfo->currcon,
- (struct fb_info *)rinfo);
- }
+ do_install_cmap(rinfo->currcon < 0 ? 0 : rinfo->currcon,
+ (struct fb_info *)rinfo);
+ /* Allow fbdev to tap us again */
+ radeon_set_dispsw(rinfo, disp);
+ /* Unblank screen */
radeonfb_blank(0, (struct fb_info *)rinfo);
+ release_console_sem();
break;
}
}
@@ -2973,6 +4386,7 @@
{
struct radeonfb_info *rinfo = (struct radeonfb_info *)(p->fb_info);
u32 dp_cntl = DST_LAST_PEL;
+ u32 dp_cntl_save = 0;
srcx *= fontwidth(p);
srcy *= fontheight(p);
@@ -2982,17 +4396,19 @@
height *= fontheight(p);
if (srcy < dsty) {
- srcy += height - 1;
- dsty += height - 1;
+ srcy += height;
+ dsty += height;
} else
dp_cntl |= DST_Y_TOP_TO_BOTTOM;
if (srcx < dstx) {
- srcx += width - 1;
- dstx += width - 1;
+ srcx += width;
+ dstx += width;
} else
dp_cntl |= DST_X_LEFT_TO_RIGHT;
+ dp_cntl_save = INREG(DP_CNTL);
+
radeon_fifo_wait(6);
OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
GMC_BRUSH_NONE |
@@ -3004,11 +4420,39 @@
OUTREG(SRC_Y_X, (srcy << 16) | srcx);
OUTREG(DST_Y_X, (dsty << 16) | dstx);
OUTREG(DST_HEIGHT_WIDTH, (height << 16) | width);
+
+ radeon_fifo_wait(1);
+ OUTREG(DP_CNTL, dp_cntl_save);
+
+ radeon_engine_idle();
+}
+
+
+
+static void radeon_rectfill(struct radeonfb_info *rinfo,
+ int dsty, int dstx,
+ int height, int width,
+ u32 clr)
+{
+ radeon_fifo_wait(6);
+ OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
+ GMC_BRUSH_SOLID_COLOR |
+ GMC_SRC_DATATYPE_COLOR |
+ ROP3_P));
+ OUTREG(DP_BRUSH_FRGD_CLR, clr);
+ OUTREG(DP_WRITE_MSK, 0xffffffff);
+ OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
+ OUTREG(DST_Y_X, (dsty << 16) | dstx);
+ OUTREG(DST_WIDTH_HEIGHT, (width << 16) | height);
+
+ radeon_engine_idle();
}
-static void fbcon_radeon_clear(struct vc_data *conp, struct display *p,
+#ifdef FBCON_HAS_CFB8
+
+static void fbcon_radeon8_clear(struct vc_data *conp, struct display *p,
int srcy, int srcx, int height, int width)
{
struct radeonfb_info *rinfo = (struct radeonfb_info *)(p->fb_info);
@@ -3023,25 +4467,15 @@
width *= fontwidth(p);
height *= fontheight(p);
- radeon_fifo_wait(6);
- OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
- GMC_BRUSH_SOLID_COLOR |
- GMC_SRC_DATATYPE_COLOR |
- ROP3_P));
- OUTREG(DP_BRUSH_FRGD_CLR, clr);
- OUTREG(DP_WRITE_MSK, 0xffffffff);
- OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
- OUTREG(DST_Y_X, (srcy << 16) | srcx);
- OUTREG(DST_WIDTH_HEIGHT, (width << 16) | height);
+ radeon_rectfill(rinfo, srcy, srcx, height, width, clr);
}
-#ifdef FBCON_HAS_CFB8
static struct display_switch fbcon_radeon8 = {
setup: fbcon_cfb8_setup,
bmove: fbcon_radeon_bmove,
- clear: fbcon_radeon_clear,
+ clear: fbcon_radeon8_clear,
putc: fbcon_cfb8_putc,
putcs: fbcon_cfb8_putcs,
revc: fbcon_cfb8_revc,
@@ -3049,3 +4483,71 @@
fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
+
+#ifdef FBCON_HAS_CFB16
+
+
+static void fbcon_radeon16_clear(struct vc_data *conp, struct display *p,
+ int srcy, int srcx, int height, int width)
+{
+ struct radeonfb_info *rinfo = (struct radeonfb_info *)(p->fb_info);
+ u32 clr;
+
+ clr = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+ clr |= (clr << 16);
+
+ srcx *= fontwidth(p);
+ srcy *= fontheight(p);
+ width *= fontwidth(p);
+ height *= fontheight(p);
+
+ radeon_rectfill(rinfo, srcy, srcx, height, width, clr);
+}
+
+
+
+static struct display_switch fbcon_radeon16 = {
+ setup: fbcon_cfb16_setup,
+ bmove: fbcon_radeon_bmove,
+ clear: fbcon_radeon16_clear,
+ putc: fbcon_cfb16_putc,
+ putcs: fbcon_cfb16_putcs,
+ revc: fbcon_cfb16_revc,
+ clear_margins: fbcon_cfb16_clear_margins,
+ fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB32
+
+
+static void fbcon_radeon32_clear(struct vc_data *conp, struct display *p,
+ int srcy, int srcx, int height, int width)
+{
+ struct radeonfb_info *rinfo = (struct radeonfb_info *)(p->fb_info);
+ u32 clr;
+
+ clr = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+
+ srcx *= fontwidth(p);
+ srcy *= fontheight(p);
+ width *= fontwidth(p);
+ height *= fontheight(p);
+
+ radeon_rectfill(rinfo, srcy, srcx, height, width, clr);
+}
+
+
+
+static struct display_switch fbcon_radeon32 = {
+ setup: fbcon_cfb32_setup,
+ bmove: fbcon_radeon_bmove,
+ clear: fbcon_radeon32_clear,
+ putc: fbcon_cfb32_putc,
+ putcs: fbcon_cfb32_putcs,
+ revc: fbcon_cfb32_revc,
+ clear_margins: fbcon_cfb32_clear_margins,
+ fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)