11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/video/offb.c -- Open Firmware based frame buffer device 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1997 Geert Uytterhoeven 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver is partly based on the PowerMac console driver: 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1996 Paul Mackerras 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * License. See the file COPYING in the main directory of this archive for 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * more details. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 2222ae782f86b726f9cea752c0f269ff6dcdf2f6e1Grant Likely#include <linux/of.h> 2322ae782f86b726f9cea752c0f269ff6dcdf2f6e1Grant Likely#include <linux/of_address.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fb.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 28f365cfd0d8b6d8fb3583d23d48f54efa88ee8563Paul Mackerras#include <linux/pci.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PPC64 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pci-bridge.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PPC32 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/bootx.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "macmodes.h" 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Supported palette hacks */ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum { 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmap_unknown, 449b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt cmap_simple, /* ATI Mach64 */ 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmap_r128, /* ATI Rage128 */ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmap_M3A, /* ATI Rage Mobility M3 Head A */ 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmap_M3B, /* ATI Rage Mobility M3 Head B */ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmap_radeon, /* ATI Radeon */ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmap_gxt2000, /* IBM GXT2000 */ 5057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt cmap_avivo, /* ATI R5xx */ 519b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt cmap_qemu, /* qemu vga */ 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct offb_par { 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile void __iomem *cmap_adr; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile void __iomem *cmap_data; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmap_type; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int blanked; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct offb_par default_par; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PPC32 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern boot_infos_t *boot_infos; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt/* Definitions used by the Avivo palette hack */ 6857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUT_RW_SELECT 0x6480 6957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUT_RW_MODE 0x6484 7057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUT_RW_INDEX 0x6488 7157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUT_SEQ_COLOR 0x648c 7257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUT_PWL_DATA 0x6490 7357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUT_30_COLOR 0x6494 7457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498 7557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c 7657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUT_AUTOFILL 0x64a0 7757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt 7857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTA_CONTROL 0x64c0 7957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4 8057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8 8157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc 8257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0 8357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 8457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 8557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt 8657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTB_CONTROL 0x6cc0 8757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4 8857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8 8957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc 9057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0 9157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4 9257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt#define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set a single color register. The values supplied are already 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rounded down to the hardware's capabilities (according to the 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * entries in the var structure). Return != 0 for invalid regno. 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int transp, struct fb_info *info) 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct offb_par *par = (struct offb_par *) info->par; 1041bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt 1051bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 1061bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt u32 *pal = info->pseudo_palette; 1071bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt u32 cr = red >> (16 - info->var.red.length); 1081bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt u32 cg = green >> (16 - info->var.green.length); 1091bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt u32 cb = blue >> (16 - info->var.blue.length); 1101bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt u32 value; 1111bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt 1121bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt if (regno >= 16) 1131bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt return -EINVAL; 1141bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt 1151bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt value = (cr << info->var.red.offset) | 1161bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt (cg << info->var.green.offset) | 1171bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt (cb << info->var.blue.offset); 1181bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt if (info->var.transp.length > 0) { 1191bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt u32 mask = (1 << info->var.transp.length) - 1; 1201bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt mask <<= info->var.transp.offset; 1211bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt value |= mask; 122ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt } 1231bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt pal[regno] = value; 1241bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt return 0; 125ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt } 126ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt 1271bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt if (regno > 255) 1281bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt return -EINVAL; 1291bb0b7d21584b3f878e2bc880db62351ddee5185Benjamin Herrenschmidt 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds red >>= 8; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds green >>= 8; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blue >>= 8; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 134ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt if (!par->cmap_adr) 135ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt return 0; 136ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (par->cmap_type) { 1389b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt case cmap_simple: 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(regno, par->cmap_adr); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(red, par->cmap_data); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(green, par->cmap_data); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(blue, par->cmap_data); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case cmap_M3A: 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_le32(par->cmap_adr + 0x58, 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in_le32(par->cmap_adr + 0x58) & ~0x20); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case cmap_r128: 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set palette index & data */ 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_8(par->cmap_adr + 0xb0, regno); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_le32(par->cmap_adr + 0xb4, 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (red << 16 | green << 8 | blue)); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case cmap_M3B: 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_le32(par->cmap_adr + 0x58, 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in_le32(par->cmap_adr + 0x58) | 0x20); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set palette index & data */ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_8(par->cmap_adr + 0xb0, regno); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue)); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case cmap_radeon: 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set palette index & data (could be smarter) */ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_8(par->cmap_adr + 0xb0, regno); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue)); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case cmap_gxt2000: 168441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt out_le32(((unsigned __iomem *) par->cmap_adr) + regno, 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (red << 16 | green << 8 | blue)); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 17157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt case cmap_avivo: 17257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt /* Write to both LUTs for now */ 17357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 17457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 17557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(((red) << 22) | ((green) << 12) | ((blue) << 2), 17657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 17757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 17857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 17957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(((red) << 22) | ((green) << 12) | ((blue) << 2), 18057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 18157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt break; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Blank the display. 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int offb_blank(int blank, struct fb_info *info) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct offb_par *par = (struct offb_par *) info->par; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!par->cmap_adr) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!par->blanked) 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!blank) 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds par->blanked = blank; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (blank) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 256; i++) { 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (par->cmap_type) { 2089b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt case cmap_simple: 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(i, par->cmap_adr); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < 3; j++) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(0, par->cmap_data); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case cmap_M3A: 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_le32(par->cmap_adr + 0x58, 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in_le32(par->cmap_adr + 0x58) & ~0x20); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case cmap_r128: 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set palette index & data */ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_8(par->cmap_adr + 0xb0, i); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_le32(par->cmap_adr + 0xb4, 0); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case cmap_M3B: 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_le32(par->cmap_adr + 0x58, 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in_le32(par->cmap_adr + 0x58) | 0x20); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set palette index & data */ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_8(par->cmap_adr + 0xb0, i); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_le32(par->cmap_adr + 0xb4, 0); 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case cmap_radeon: 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_8(par->cmap_adr + 0xb0, i); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_le32(par->cmap_adr + 0xb4, 0); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case cmap_gxt2000: 235441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt out_le32(((unsigned __iomem *) par->cmap_adr) + i, 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt case cmap_avivo: 23957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 24057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 24157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 24257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 24357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 24457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 24557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt break; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fb_set_cmap(&info->cmap, info); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidtstatic int offb_set_par(struct fb_info *info) 25357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt{ 25457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt struct offb_par *par = (struct offb_par *) info->par; 25557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt 25657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt /* On avivo, initialize palette control */ 25757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt if (par->cmap_type == cmap_avivo) { 25857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUTA_CONTROL); 25957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_BLUE); 26057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_GREEN); 26157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_RED); 26257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_BLUE); 26357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_GREEN); 26457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_RED); 26557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUTB_CONTROL); 26657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_BLUE); 26757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_GREEN); 26857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_RED); 26957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_BLUE); 27057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_GREEN); 27157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_RED); 27257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 27357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE); 27457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK); 27557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 27657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE); 27757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK); 27857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt } 27957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt return 0; 28057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt} 28157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt 282ceae8cbe94f3127253110e2d01b9334069e93177Dave Airliestatic void offb_destroy(struct fb_info *info) 283ceae8cbe94f3127253110e2d01b9334069e93177Dave Airlie{ 284ceae8cbe94f3127253110e2d01b9334069e93177Dave Airlie if (info->screen_base) 285ceae8cbe94f3127253110e2d01b9334069e93177Dave Airlie iounmap(info->screen_base); 2861471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); 287ceae8cbe94f3127253110e2d01b9334069e93177Dave Airlie framebuffer_release(info); 288ceae8cbe94f3127253110e2d01b9334069e93177Dave Airlie} 289ceae8cbe94f3127253110e2d01b9334069e93177Dave Airlie 29057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidtstatic struct fb_ops offb_ops = { 29157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt .owner = THIS_MODULE, 292ceae8cbe94f3127253110e2d01b9334069e93177Dave Airlie .fb_destroy = offb_destroy, 29357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt .fb_setcolreg = offb_setcolreg, 29457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt .fb_set_par = offb_set_par, 29557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt .fb_blank = offb_blank, 29657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt .fb_fillrect = cfb_fillrect, 29757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt .fb_copyarea = cfb_copyarea, 29857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt .fb_imageblit = cfb_imageblit, 29957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt}; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidtstatic void __iomem *offb_map_reg(struct device_node *np, int index, 30273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt unsigned long offset, unsigned long size) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 304441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt const u32 *addrp; 305441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt u64 asize, taddr; 306441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt unsigned int flags; 307441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt 308441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt addrp = of_get_pci_address(np, index, &asize, &flags); 309441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt if (addrp == NULL) 310441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt addrp = of_get_address(np, index, &asize, &flags); 311441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt if (addrp == NULL) 312441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt return NULL; 313441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) 314441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt return NULL; 315441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt if ((offset + size) > asize) 316441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt return NULL; 317441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt taddr = of_translate_address(np, addrp); 318441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt if (taddr == OF_BAD_ADDR) 319441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt return NULL; 320441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt return ioremap(taddr + offset, size); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidtstatic void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp, 32457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt const char *name, unsigned long address) 32557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt{ 32657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt struct offb_par *par = (struct offb_par *) info->par; 32757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt 32857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt if (dp && !strncmp(name, "ATY,Rage128", 11)) { 32957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); 33057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt if (par->cmap_adr) 33157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_type = cmap_r128; 33257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12) 33357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt || !strncmp(name, "ATY,RageM3p12A", 14))) { 33457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); 33557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt if (par->cmap_adr) 33657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_type = cmap_M3A; 33757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) { 33857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); 33957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt if (par->cmap_adr) 34057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_type = cmap_M3B; 34157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt } else if (dp && !strncmp(name, "ATY,Rage6", 9)) { 34257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff); 34357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt if (par->cmap_adr) 34457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_type = cmap_radeon; 34557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt } else if (!strncmp(name, "ATY,", 4)) { 34657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt unsigned long base = address & 0xff000000UL; 34757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_adr = 34857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt ioremap(base + 0x7ff000, 0x1000) + 0xcc0; 34957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_data = par->cmap_adr + 1; 3509b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt par->cmap_type = cmap_simple; 35157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt } else if (dp && (of_device_is_compatible(dp, "pci1014,b7") || 35257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt of_device_is_compatible(dp, "pci1014,21c"))) { 35357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000); 35457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt if (par->cmap_adr) 35557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_type = cmap_gxt2000; 35657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt } else if (dp && !strncmp(name, "vga,Display-", 12)) { 35757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt /* Look for AVIVO initialized by SLOF */ 35857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt struct device_node *pciparent = of_get_parent(dp); 35957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt const u32 *vid, *did; 36057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt vid = of_get_property(pciparent, "vendor-id", NULL); 36157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt did = of_get_property(pciparent, "device-id", NULL); 36257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt /* This will match most R5xx */ 36357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt if (vid && did && *vid == 0x1002 && 36457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt ((*did >= 0x7100 && *did < 0x7800) || 36557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt (*did >= 0x9400))) { 36657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_adr = offb_map_reg(pciparent, 2, 0, 0x10000); 36757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt if (par->cmap_adr) 36857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt par->cmap_type = cmap_avivo; 36957a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt } 37057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt of_node_put(pciparent); 3719b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt } else if (dp && of_device_is_compatible(dp, "qemu,std-vga")) { 3729b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt const u32 io_of_addr[3] = { 0x01000000, 0x0, 0x0 }; 3739b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt u64 io_addr = of_translate_address(dp, io_of_addr); 3749b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt if (io_addr != OF_BAD_ADDR) { 3759b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt par->cmap_adr = ioremap(io_addr + 0x3c8, 2); 3769b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt if (par->cmap_adr) { 3779b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt par->cmap_type = cmap_simple; 3789b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt par->cmap_data = par->cmap_adr + 1; 3799b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt } 3809b961ed21a7c92c4768b9871a1c7e68d90f5267dBenjamin Herrenschmidt } 38157a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt } 38257a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt info->fix.visual = (par->cmap_type != cmap_unknown) ? 38357a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; 38457a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt} 38557a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init offb_init_fb(const char *name, const char *full_name, 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int width, int height, int depth, 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pitch, unsigned long address, 3897f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov int foreign_endian, struct device_node *dp) 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 391c055fe0797b7bd8f6f21a13598a55a16d5c13ae7Benjamin Herrenschmidt unsigned long res_size = pitch * height; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct offb_par *par = &default_par; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long res_start = address; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fb_fix_screeninfo *fix; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fb_var_screeninfo *var; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fb_info *info; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_mem_region(res_start, res_size, "offb")) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n", 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds width, height, name, address, depth, pitch); 404ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt if (depth != 8 && depth != 15 && depth != 16 && depth != 32) { 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: can't use depth = %d\n", full_name, 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds depth); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_mem_region(res_start, res_size); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4114113819eb360555a91a8291f37bbbe9d26c5b275Krzysztof Helt info = framebuffer_alloc(sizeof(u32) * 16, NULL); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info == 0) { 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_mem_region(res_start, res_size); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fix = &info->fix; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var = &info->var; 42057a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt info->par = par; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(fix->id, "OFfb "); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb ")); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fix->id[sizeof(fix->id) - 1] = '\0'; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->xres = var->xres_virtual = width; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->yres = var->yres_virtual = height; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fix->line_length = pitch; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fix->smem_start = address; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fix->smem_len = pitch * height; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fix->type = FB_TYPE_PACKED_PIXELS; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fix->type_aux = 0; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds par->cmap_type = cmap_unknown; 43657a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt if (depth == 8) 43757a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt offb_init_palette_hacks(info, dp, name, address); 43857a20d8fb0d2a05abe40abd6bb29e3f923721f1bBenjamin Herrenschmidt else 43973ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt fix->visual = FB_VISUAL_TRUECOLOR; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->xoffset = var->yoffset = 0; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (depth) { 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 8: 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->bits_per_pixel = 8; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->red.offset = 0; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->red.length = 8; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->green.offset = 0; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->green.length = 8; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->blue.offset = 0; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->blue.length = 8; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->transp.offset = 0; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->transp.length = 0; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 454ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt case 15: /* RGB 555 */ 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->bits_per_pixel = 16; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->red.offset = 10; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->red.length = 5; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->green.offset = 5; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->green.length = 5; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->blue.offset = 0; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->blue.length = 5; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->transp.offset = 0; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->transp.length = 0; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 465ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt case 16: /* RGB 565 */ 466ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt var->bits_per_pixel = 16; 467ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt var->red.offset = 11; 468ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt var->red.length = 5; 469ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt var->green.offset = 5; 470ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt var->green.length = 6; 471ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt var->blue.offset = 0; 472ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt var->blue.length = 5; 473ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt var->transp.offset = 0; 474ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt var->transp.length = 0; 475ab13446616118dc61c00ea50cc49919400717dd0Benjamin Herrenschmidt break; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 32: /* RGB 888 */ 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->bits_per_pixel = 32; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->red.offset = 16; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->red.length = 8; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->green.offset = 8; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->green.length = 8; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->blue.offset = 0; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->blue.length = 8; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->transp.offset = 24; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->transp.length = 8; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->red.msb_right = var->green.msb_right = var->blue.msb_right = 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->transp.msb_right = 0; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->grayscale = 0; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->nonstd = 0; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->activate = 0; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->height = var->width = -1; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->pixclock = 10000; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->left_margin = var->right_margin = 16; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->upper_margin = var->lower_margin = 16; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->hsync_len = var->vsync_len = 8; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->sync = 0; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds var->vmode = FB_VMODE_NONINTERLACED; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501ceae8cbe94f3127253110e2d01b9334069e93177Dave Airlie /* set offb aperture size for generic probing */ 5021471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz info->apertures = alloc_apertures(1); 5031471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz if (!info->apertures) 5041471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz goto out_aper; 5051471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz info->apertures->ranges[0].base = address; 5061471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz info->apertures->ranges[0].size = fix->smem_len; 507ceae8cbe94f3127253110e2d01b9334069e93177Dave Airlie 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->fbops = &offb_ops; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->screen_base = ioremap(address, fix->smem_len); 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->pseudo_palette = (void *) (info + 1); 511ceae8cbe94f3127253110e2d01b9334069e93177Dave Airlie info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE | foreign_endian; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fb_alloc_cmap(&info->cmap, 256, 0); 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5151471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz if (register_framebuffer(info) < 0) 5161471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz goto out_err; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n", 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->node, full_name); 5201471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz return; 5211471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz 5221471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarzout_err: 5231471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz iounmap(info->screen_base); 5241471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarzout_aper: 5251471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz iounmap(par->cmap_adr); 5261471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz par->cmap_adr = NULL; 5271471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz framebuffer_release(info); 5281471ca9aa71cd37b6a7476bb6f06a3a8622ea1bdMarcin Slusarz release_mem_region(res_start, res_size); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 53273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidtstatic void __init offb_init_nodriver(struct device_node *dp, int no_real_node) 53373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt{ 53473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt unsigned int len; 53573ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt int i, width = 640, height = 480, depth = 8, pitch = 640; 53673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt unsigned int flags, rsize, addr_prop = 0; 53773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt unsigned long max_size = 0; 53873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt u64 rstart, address = OF_BAD_ADDR; 539b04e3dd4ab4c7763a4ca8f751caaf69ce8dabbbaJeremy Kerr const u32 *pp, *addrp, *up; 54073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt u64 asize; 5417f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov int foreign_endian = 0; 5427f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov 5437f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov#ifdef __BIG_ENDIAN 5447f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov if (of_get_property(dp, "little-endian", NULL)) 5457f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov foreign_endian = FBINFO_FOREIGN_ENDIAN; 5467f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov#else 5477f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov if (of_get_property(dp, "big-endian", NULL)) 5487f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov foreign_endian = FBINFO_FOREIGN_ENDIAN; 5497f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov#endif 55073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 55140cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell pp = of_get_property(dp, "linux,bootx-depth", &len); 55273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (pp == NULL) 55340cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell pp = of_get_property(dp, "depth", &len); 55473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (pp && len == sizeof(u32)) 55573ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt depth = *pp; 55673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 55740cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell pp = of_get_property(dp, "linux,bootx-width", &len); 55873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (pp == NULL) 55940cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell pp = of_get_property(dp, "width", &len); 56073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (pp && len == sizeof(u32)) 56173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt width = *pp; 56273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 56340cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell pp = of_get_property(dp, "linux,bootx-height", &len); 56473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (pp == NULL) 56540cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell pp = of_get_property(dp, "height", &len); 56673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (pp && len == sizeof(u32)) 56773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt height = *pp; 56873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 56940cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell pp = of_get_property(dp, "linux,bootx-linebytes", &len); 57073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (pp == NULL) 57140cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell pp = of_get_property(dp, "linebytes", &len); 572441cbd8dace80545db2ac43175ac1c097d96f75cBenjamin Herrenschmidt if (pp && len == sizeof(u32) && (*pp != 0xffffffffu)) 57373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt pitch = *pp; 57473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt else 57573ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt pitch = width * ((depth + 7) / 8); 57673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 57773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt rsize = (unsigned long)pitch * (unsigned long)height; 57873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 57973ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt /* Ok, now we try to figure out the address of the framebuffer. 58073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * 58173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * Unfortunately, Open Firmware doesn't provide a standard way to do 58273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * so. All we can do is a dodgy heuristic that happens to work in 58373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * practice. On most machines, the "address" property contains what 58473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * we need, though not on Matrox cards found in IBM machines. What I've 58573ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * found that appears to give good results is to go through the PCI 58673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * ranges and pick one that is both big enough and if possible encloses 58773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * the "address" property. If none match, we pick the biggest 58873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt */ 58940cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell up = of_get_property(dp, "linux,bootx-addr", &len); 59073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (up == NULL) 59140cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell up = of_get_property(dp, "address", &len); 59273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (up && len == sizeof(u32)) 59373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt addr_prop = *up; 59473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 59573ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt /* Hack for when BootX is passing us */ 59673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (no_real_node) 59773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt goto skip_addr; 59873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 59973ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags)) 60073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt != NULL; i++) { 60173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt int match_addrp = 0; 60273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 60373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (!(flags & IORESOURCE_MEM)) 60473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt continue; 60573ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (asize < rsize) 60673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt continue; 60773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt rstart = of_translate_address(dp, addrp); 60873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (rstart == OF_BAD_ADDR) 60973ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt continue; 61073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (addr_prop && (rstart <= addr_prop) && 61173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt ((rstart + asize) >= (addr_prop + rsize))) 61273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt match_addrp = 1; 61373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (match_addrp) { 61473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt address = addr_prop; 61573ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt break; 61673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt } 61773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (rsize > max_size) { 61873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt max_size = rsize; 61973ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt address = OF_BAD_ADDR; 62073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt } 62173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 62273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (address == OF_BAD_ADDR) 62373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt address = rstart; 62473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt } 62573ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt skip_addr: 62673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (address == OF_BAD_ADDR && addr_prop) 62773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt address = (u64)addr_prop; 62873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (address != OF_BAD_ADDR) { 62973ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt /* kludge for valkyrie */ 63073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (strcmp(dp->name, "valkyrie") == 0) 63173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt address += 0x1000; 63273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt offb_init_fb(no_real_node ? "bootx" : dp->name, 63373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt no_real_node ? "display" : dp->full_name, 63473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt width, height, depth, pitch, address, 6357f29b87a7779505288a31df16ba84a85fc1ae93cAnton Vorontsov foreign_endian, no_real_node ? NULL : dp); 63673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt } 63773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt} 63873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 63973ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidtstatic int __init offb_init(void) 64073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt{ 64173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt struct device_node *dp = NULL, *boot_disp = NULL; 64273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 64373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt if (fb_get_options("offb", NULL)) 64473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt return -ENODEV; 64573ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 64673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt /* Check if we have a MacOS display without a node spec */ 64740cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell if (of_get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) { 64873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt /* The old code tried to work out which node was the MacOS 64973ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * display based on the address. I'm dropping that since the 65073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * lack of a node spec only happens with old BootX versions 65173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * (users can update) and with this code, they'll still get 65273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt * a display (just not the palette hacks). 65373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt */ 65473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt offb_init_nodriver(of_chosen, 1); 65573ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt } 65673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 65773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { 65840cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell if (of_get_property(dp, "linux,opened", NULL) && 65940cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell of_get_property(dp, "linux,boot-display", NULL)) { 66073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt boot_disp = dp; 66173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt offb_init_nodriver(dp, 0); 66273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt } 66373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt } 66473ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { 66540cd3a4564ed6b7bc0279430120ca0e9b83cf486Stephen Rothwell if (of_get_property(dp, "linux,opened", NULL) && 66673ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt dp != boot_disp) 66773ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt offb_init_nodriver(dp, 0); 66873ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt } 66973ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 67073ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt return 0; 67173ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt} 67273ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 67373ea6959b11821ba5ade77fb1d3d4aed52be3b67Benjamin Herrenschmidt 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(offb_init); 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 676