1f7018c21STomi Valkeinen /* 2f7018c21STomi Valkeinen * linux/drivers/video/offb.c -- Open Firmware based frame buffer device 3f7018c21STomi Valkeinen * 4f7018c21STomi Valkeinen * Copyright (C) 1997 Geert Uytterhoeven 5f7018c21STomi Valkeinen * 6f7018c21STomi Valkeinen * This driver is partly based on the PowerMac console driver: 7f7018c21STomi Valkeinen * 8f7018c21STomi Valkeinen * Copyright (C) 1996 Paul Mackerras 9f7018c21STomi Valkeinen * 10f7018c21STomi Valkeinen * This file is subject to the terms and conditions of the GNU General Public 11f7018c21STomi Valkeinen * License. See the file COPYING in the main directory of this archive for 12f7018c21STomi Valkeinen * more details. 13f7018c21STomi Valkeinen */ 14f7018c21STomi Valkeinen 15f7018c21STomi Valkeinen #include <linux/module.h> 16f7018c21STomi Valkeinen #include <linux/kernel.h> 17f7018c21STomi Valkeinen #include <linux/errno.h> 18f7018c21STomi Valkeinen #include <linux/string.h> 19f7018c21STomi Valkeinen #include <linux/mm.h> 20f7018c21STomi Valkeinen #include <linux/vmalloc.h> 21f7018c21STomi Valkeinen #include <linux/delay.h> 22f7018c21STomi Valkeinen #include <linux/of.h> 23f7018c21STomi Valkeinen #include <linux/of_address.h> 24f7018c21STomi Valkeinen #include <linux/interrupt.h> 25f7018c21STomi Valkeinen #include <linux/fb.h> 26f7018c21STomi Valkeinen #include <linux/init.h> 27f7018c21STomi Valkeinen #include <linux/ioport.h> 28f7018c21STomi Valkeinen #include <linux/pci.h> 29f7018c21STomi Valkeinen #include <asm/io.h> 30f7018c21STomi Valkeinen 31f7018c21STomi Valkeinen #ifdef CONFIG_PPC32 32f7018c21STomi Valkeinen #include <asm/bootx.h> 33f7018c21STomi Valkeinen #endif 34f7018c21STomi Valkeinen 35f7018c21STomi Valkeinen #include "macmodes.h" 36f7018c21STomi Valkeinen 37f7018c21STomi Valkeinen /* Supported palette hacks */ 38f7018c21STomi Valkeinen enum { 39f7018c21STomi Valkeinen cmap_unknown, 40f7018c21STomi Valkeinen cmap_simple, /* ATI Mach64 */ 41f7018c21STomi Valkeinen cmap_r128, /* ATI Rage128 */ 42f7018c21STomi Valkeinen cmap_M3A, /* ATI Rage Mobility M3 Head A */ 43f7018c21STomi Valkeinen cmap_M3B, /* ATI Rage Mobility M3 Head B */ 44f7018c21STomi Valkeinen cmap_radeon, /* ATI Radeon */ 45f7018c21STomi Valkeinen cmap_gxt2000, /* IBM GXT2000 */ 46f7018c21STomi Valkeinen cmap_avivo, /* ATI R5xx */ 47f7018c21STomi Valkeinen cmap_qemu, /* qemu vga */ 48f7018c21STomi Valkeinen }; 49f7018c21STomi Valkeinen 50f7018c21STomi Valkeinen struct offb_par { 51f7018c21STomi Valkeinen volatile void __iomem *cmap_adr; 52f7018c21STomi Valkeinen volatile void __iomem *cmap_data; 53f7018c21STomi Valkeinen int cmap_type; 54f7018c21STomi Valkeinen int blanked; 55f7018c21STomi Valkeinen }; 56f7018c21STomi Valkeinen 57f7018c21STomi Valkeinen struct offb_par default_par; 58f7018c21STomi Valkeinen 59f7018c21STomi Valkeinen #ifdef CONFIG_PPC32 60f7018c21STomi Valkeinen extern boot_infos_t *boot_infos; 61f7018c21STomi Valkeinen #endif 62f7018c21STomi Valkeinen 63f7018c21STomi Valkeinen /* Definitions used by the Avivo palette hack */ 64f7018c21STomi Valkeinen #define AVIVO_DC_LUT_RW_SELECT 0x6480 65f7018c21STomi Valkeinen #define AVIVO_DC_LUT_RW_MODE 0x6484 66f7018c21STomi Valkeinen #define AVIVO_DC_LUT_RW_INDEX 0x6488 67f7018c21STomi Valkeinen #define AVIVO_DC_LUT_SEQ_COLOR 0x648c 68f7018c21STomi Valkeinen #define AVIVO_DC_LUT_PWL_DATA 0x6490 69f7018c21STomi Valkeinen #define AVIVO_DC_LUT_30_COLOR 0x6494 70f7018c21STomi Valkeinen #define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498 71f7018c21STomi Valkeinen #define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c 72f7018c21STomi Valkeinen #define AVIVO_DC_LUT_AUTOFILL 0x64a0 73f7018c21STomi Valkeinen 74f7018c21STomi Valkeinen #define AVIVO_DC_LUTA_CONTROL 0x64c0 75f7018c21STomi Valkeinen #define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4 76f7018c21STomi Valkeinen #define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8 77f7018c21STomi Valkeinen #define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc 78f7018c21STomi Valkeinen #define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0 79f7018c21STomi Valkeinen #define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 80f7018c21STomi Valkeinen #define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 81f7018c21STomi Valkeinen 82f7018c21STomi Valkeinen #define AVIVO_DC_LUTB_CONTROL 0x6cc0 83f7018c21STomi Valkeinen #define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4 84f7018c21STomi Valkeinen #define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8 85f7018c21STomi Valkeinen #define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc 86f7018c21STomi Valkeinen #define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0 87f7018c21STomi Valkeinen #define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4 88f7018c21STomi Valkeinen #define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8 89f7018c21STomi Valkeinen 90f7018c21STomi Valkeinen /* 91f7018c21STomi Valkeinen * Set a single color register. The values supplied are already 92f7018c21STomi Valkeinen * rounded down to the hardware's capabilities (according to the 93f7018c21STomi Valkeinen * entries in the var structure). Return != 0 for invalid regno. 94f7018c21STomi Valkeinen */ 95f7018c21STomi Valkeinen 96f7018c21STomi Valkeinen static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 97f7018c21STomi Valkeinen u_int transp, struct fb_info *info) 98f7018c21STomi Valkeinen { 99f7018c21STomi Valkeinen struct offb_par *par = (struct offb_par *) info->par; 100f7018c21STomi Valkeinen 101f7018c21STomi Valkeinen if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 102f7018c21STomi Valkeinen u32 *pal = info->pseudo_palette; 103f7018c21STomi Valkeinen u32 cr = red >> (16 - info->var.red.length); 104f7018c21STomi Valkeinen u32 cg = green >> (16 - info->var.green.length); 105f7018c21STomi Valkeinen u32 cb = blue >> (16 - info->var.blue.length); 106f7018c21STomi Valkeinen u32 value; 107f7018c21STomi Valkeinen 108f7018c21STomi Valkeinen if (regno >= 16) 109f7018c21STomi Valkeinen return -EINVAL; 110f7018c21STomi Valkeinen 111f7018c21STomi Valkeinen value = (cr << info->var.red.offset) | 112f7018c21STomi Valkeinen (cg << info->var.green.offset) | 113f7018c21STomi Valkeinen (cb << info->var.blue.offset); 114f7018c21STomi Valkeinen if (info->var.transp.length > 0) { 115f7018c21STomi Valkeinen u32 mask = (1 << info->var.transp.length) - 1; 116f7018c21STomi Valkeinen mask <<= info->var.transp.offset; 117f7018c21STomi Valkeinen value |= mask; 118f7018c21STomi Valkeinen } 11968986c9fSBenjamin Herrenschmidt pal[regno] = value; 120f7018c21STomi Valkeinen return 0; 121f7018c21STomi Valkeinen } 122f7018c21STomi Valkeinen 123f7018c21STomi Valkeinen if (regno > 255) 124f7018c21STomi Valkeinen return -EINVAL; 125f7018c21STomi Valkeinen 126f7018c21STomi Valkeinen red >>= 8; 127f7018c21STomi Valkeinen green >>= 8; 128f7018c21STomi Valkeinen blue >>= 8; 129f7018c21STomi Valkeinen 130f7018c21STomi Valkeinen if (!par->cmap_adr) 131f7018c21STomi Valkeinen return 0; 132f7018c21STomi Valkeinen 133f7018c21STomi Valkeinen switch (par->cmap_type) { 134f7018c21STomi Valkeinen case cmap_simple: 135f7018c21STomi Valkeinen writeb(regno, par->cmap_adr); 136f7018c21STomi Valkeinen writeb(red, par->cmap_data); 137f7018c21STomi Valkeinen writeb(green, par->cmap_data); 138f7018c21STomi Valkeinen writeb(blue, par->cmap_data); 139f7018c21STomi Valkeinen break; 140f7018c21STomi Valkeinen case cmap_M3A: 141f7018c21STomi Valkeinen /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ 142f7018c21STomi Valkeinen out_le32(par->cmap_adr + 0x58, 143f7018c21STomi Valkeinen in_le32(par->cmap_adr + 0x58) & ~0x20); 144f7018c21STomi Valkeinen case cmap_r128: 145f7018c21STomi Valkeinen /* Set palette index & data */ 146f7018c21STomi Valkeinen out_8(par->cmap_adr + 0xb0, regno); 147f7018c21STomi Valkeinen out_le32(par->cmap_adr + 0xb4, 148f7018c21STomi Valkeinen (red << 16 | green << 8 | blue)); 149f7018c21STomi Valkeinen break; 150f7018c21STomi Valkeinen case cmap_M3B: 151f7018c21STomi Valkeinen /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ 152f7018c21STomi Valkeinen out_le32(par->cmap_adr + 0x58, 153f7018c21STomi Valkeinen in_le32(par->cmap_adr + 0x58) | 0x20); 154f7018c21STomi Valkeinen /* Set palette index & data */ 155f7018c21STomi Valkeinen out_8(par->cmap_adr + 0xb0, regno); 156f7018c21STomi Valkeinen out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue)); 157f7018c21STomi Valkeinen break; 158f7018c21STomi Valkeinen case cmap_radeon: 159f7018c21STomi Valkeinen /* Set palette index & data (could be smarter) */ 160f7018c21STomi Valkeinen out_8(par->cmap_adr + 0xb0, regno); 161f7018c21STomi Valkeinen out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue)); 162f7018c21STomi Valkeinen break; 163f7018c21STomi Valkeinen case cmap_gxt2000: 164f7018c21STomi Valkeinen out_le32(((unsigned __iomem *) par->cmap_adr) + regno, 165f7018c21STomi Valkeinen (red << 16 | green << 8 | blue)); 166f7018c21STomi Valkeinen break; 167f7018c21STomi Valkeinen case cmap_avivo: 168f7018c21STomi Valkeinen /* Write to both LUTs for now */ 169f7018c21STomi Valkeinen writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 170f7018c21STomi Valkeinen writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 171f7018c21STomi Valkeinen writel(((red) << 22) | ((green) << 12) | ((blue) << 2), 172f7018c21STomi Valkeinen par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 173f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 174f7018c21STomi Valkeinen writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 175f7018c21STomi Valkeinen writel(((red) << 22) | ((green) << 12) | ((blue) << 2), 176f7018c21STomi Valkeinen par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 177f7018c21STomi Valkeinen break; 178f7018c21STomi Valkeinen } 179f7018c21STomi Valkeinen 180f7018c21STomi Valkeinen return 0; 181f7018c21STomi Valkeinen } 182f7018c21STomi Valkeinen 183f7018c21STomi Valkeinen /* 184f7018c21STomi Valkeinen * Blank the display. 185f7018c21STomi Valkeinen */ 186f7018c21STomi Valkeinen 187f7018c21STomi Valkeinen static int offb_blank(int blank, struct fb_info *info) 188f7018c21STomi Valkeinen { 189f7018c21STomi Valkeinen struct offb_par *par = (struct offb_par *) info->par; 190f7018c21STomi Valkeinen int i, j; 191f7018c21STomi Valkeinen 192f7018c21STomi Valkeinen if (!par->cmap_adr) 193f7018c21STomi Valkeinen return 0; 194f7018c21STomi Valkeinen 195f7018c21STomi Valkeinen if (!par->blanked) 196f7018c21STomi Valkeinen if (!blank) 197f7018c21STomi Valkeinen return 0; 198f7018c21STomi Valkeinen 199f7018c21STomi Valkeinen par->blanked = blank; 200f7018c21STomi Valkeinen 201f7018c21STomi Valkeinen if (blank) 202f7018c21STomi Valkeinen for (i = 0; i < 256; i++) { 203f7018c21STomi Valkeinen switch (par->cmap_type) { 204f7018c21STomi Valkeinen case cmap_simple: 205f7018c21STomi Valkeinen writeb(i, par->cmap_adr); 206f7018c21STomi Valkeinen for (j = 0; j < 3; j++) 207f7018c21STomi Valkeinen writeb(0, par->cmap_data); 208f7018c21STomi Valkeinen break; 209f7018c21STomi Valkeinen case cmap_M3A: 210f7018c21STomi Valkeinen /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ 211f7018c21STomi Valkeinen out_le32(par->cmap_adr + 0x58, 212f7018c21STomi Valkeinen in_le32(par->cmap_adr + 0x58) & ~0x20); 213f7018c21STomi Valkeinen case cmap_r128: 214f7018c21STomi Valkeinen /* Set palette index & data */ 215f7018c21STomi Valkeinen out_8(par->cmap_adr + 0xb0, i); 216f7018c21STomi Valkeinen out_le32(par->cmap_adr + 0xb4, 0); 217f7018c21STomi Valkeinen break; 218f7018c21STomi Valkeinen case cmap_M3B: 219f7018c21STomi Valkeinen /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ 220f7018c21STomi Valkeinen out_le32(par->cmap_adr + 0x58, 221f7018c21STomi Valkeinen in_le32(par->cmap_adr + 0x58) | 0x20); 222f7018c21STomi Valkeinen /* Set palette index & data */ 223f7018c21STomi Valkeinen out_8(par->cmap_adr + 0xb0, i); 224f7018c21STomi Valkeinen out_le32(par->cmap_adr + 0xb4, 0); 225f7018c21STomi Valkeinen break; 226f7018c21STomi Valkeinen case cmap_radeon: 227f7018c21STomi Valkeinen out_8(par->cmap_adr + 0xb0, i); 228f7018c21STomi Valkeinen out_le32(par->cmap_adr + 0xb4, 0); 229f7018c21STomi Valkeinen break; 230f7018c21STomi Valkeinen case cmap_gxt2000: 231f7018c21STomi Valkeinen out_le32(((unsigned __iomem *) par->cmap_adr) + i, 232f7018c21STomi Valkeinen 0); 233f7018c21STomi Valkeinen break; 234f7018c21STomi Valkeinen case cmap_avivo: 235f7018c21STomi Valkeinen writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 236f7018c21STomi Valkeinen writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 237f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 238f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 239f7018c21STomi Valkeinen writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 240f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 241f7018c21STomi Valkeinen break; 242f7018c21STomi Valkeinen } 243f7018c21STomi Valkeinen } else 244f7018c21STomi Valkeinen fb_set_cmap(&info->cmap, info); 245f7018c21STomi Valkeinen return 0; 246f7018c21STomi Valkeinen } 247f7018c21STomi Valkeinen 248f7018c21STomi Valkeinen static int offb_set_par(struct fb_info *info) 249f7018c21STomi Valkeinen { 250f7018c21STomi Valkeinen struct offb_par *par = (struct offb_par *) info->par; 251f7018c21STomi Valkeinen 252f7018c21STomi Valkeinen /* On avivo, initialize palette control */ 253f7018c21STomi Valkeinen if (par->cmap_type == cmap_avivo) { 254f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUTA_CONTROL); 255f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_BLUE); 256f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_GREEN); 257f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_RED); 258f7018c21STomi Valkeinen writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_BLUE); 259f7018c21STomi Valkeinen writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_GREEN); 260f7018c21STomi Valkeinen writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_RED); 261f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUTB_CONTROL); 262f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_BLUE); 263f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_GREEN); 264f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_RED); 265f7018c21STomi Valkeinen writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_BLUE); 266f7018c21STomi Valkeinen writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_GREEN); 267f7018c21STomi Valkeinen writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_RED); 268f7018c21STomi Valkeinen writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 269f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE); 270f7018c21STomi Valkeinen writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK); 271f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 272f7018c21STomi Valkeinen writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE); 273f7018c21STomi Valkeinen writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK); 274f7018c21STomi Valkeinen } 275f7018c21STomi Valkeinen return 0; 276f7018c21STomi Valkeinen } 277f7018c21STomi Valkeinen 278f7018c21STomi Valkeinen static void offb_destroy(struct fb_info *info) 279f7018c21STomi Valkeinen { 280f7018c21STomi Valkeinen if (info->screen_base) 281f7018c21STomi Valkeinen iounmap(info->screen_base); 282f7018c21STomi Valkeinen release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); 2839cbaf4d9SMathieu Malaterre fb_dealloc_cmap(&info->cmap); 284f7018c21STomi Valkeinen framebuffer_release(info); 285f7018c21STomi Valkeinen } 286f7018c21STomi Valkeinen 287f7018c21STomi Valkeinen static struct fb_ops offb_ops = { 288f7018c21STomi Valkeinen .owner = THIS_MODULE, 289f7018c21STomi Valkeinen .fb_destroy = offb_destroy, 290f7018c21STomi Valkeinen .fb_setcolreg = offb_setcolreg, 291f7018c21STomi Valkeinen .fb_set_par = offb_set_par, 292f7018c21STomi Valkeinen .fb_blank = offb_blank, 293f7018c21STomi Valkeinen .fb_fillrect = cfb_fillrect, 294f7018c21STomi Valkeinen .fb_copyarea = cfb_copyarea, 295f7018c21STomi Valkeinen .fb_imageblit = cfb_imageblit, 296f7018c21STomi Valkeinen }; 297f7018c21STomi Valkeinen 298f7018c21STomi Valkeinen static void __iomem *offb_map_reg(struct device_node *np, int index, 299f7018c21STomi Valkeinen unsigned long offset, unsigned long size) 300f7018c21STomi Valkeinen { 301f7018c21STomi Valkeinen const __be32 *addrp; 302f7018c21STomi Valkeinen u64 asize, taddr; 303f7018c21STomi Valkeinen unsigned int flags; 304f7018c21STomi Valkeinen 305f7018c21STomi Valkeinen addrp = of_get_pci_address(np, index, &asize, &flags); 306f7018c21STomi Valkeinen if (addrp == NULL) 307f7018c21STomi Valkeinen addrp = of_get_address(np, index, &asize, &flags); 308f7018c21STomi Valkeinen if (addrp == NULL) 309f7018c21STomi Valkeinen return NULL; 310f7018c21STomi Valkeinen if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) 311f7018c21STomi Valkeinen return NULL; 312f7018c21STomi Valkeinen if ((offset + size) > asize) 313f7018c21STomi Valkeinen return NULL; 314f7018c21STomi Valkeinen taddr = of_translate_address(np, addrp); 315f7018c21STomi Valkeinen if (taddr == OF_BAD_ADDR) 316f7018c21STomi Valkeinen return NULL; 317f7018c21STomi Valkeinen return ioremap(taddr + offset, size); 318f7018c21STomi Valkeinen } 319f7018c21STomi Valkeinen 320f7018c21STomi Valkeinen static void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp, 32100257e0cSRob Herring unsigned long address) 322f7018c21STomi Valkeinen { 323f7018c21STomi Valkeinen struct offb_par *par = (struct offb_par *) info->par; 324f7018c21STomi Valkeinen 32500257e0cSRob Herring if (of_node_name_prefix(dp, "ATY,Rage128")) { 326f7018c21STomi Valkeinen par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); 327f7018c21STomi Valkeinen if (par->cmap_adr) 328f7018c21STomi Valkeinen par->cmap_type = cmap_r128; 32900257e0cSRob Herring } else if (of_node_name_prefix(dp, "ATY,RageM3pA") || 33000257e0cSRob Herring of_node_name_prefix(dp, "ATY,RageM3p12A")) { 331f7018c21STomi Valkeinen par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); 332f7018c21STomi Valkeinen if (par->cmap_adr) 333f7018c21STomi Valkeinen par->cmap_type = cmap_M3A; 33400257e0cSRob Herring } else if (of_node_name_prefix(dp, "ATY,RageM3pB")) { 335f7018c21STomi Valkeinen par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); 336f7018c21STomi Valkeinen if (par->cmap_adr) 337f7018c21STomi Valkeinen par->cmap_type = cmap_M3B; 33800257e0cSRob Herring } else if (of_node_name_prefix(dp, "ATY,Rage6")) { 339f7018c21STomi Valkeinen par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff); 340f7018c21STomi Valkeinen if (par->cmap_adr) 341f7018c21STomi Valkeinen par->cmap_type = cmap_radeon; 34200257e0cSRob Herring } else if (of_node_name_prefix(dp, "ATY,")) { 343f7018c21STomi Valkeinen unsigned long base = address & 0xff000000UL; 344f7018c21STomi Valkeinen par->cmap_adr = 345f7018c21STomi Valkeinen ioremap(base + 0x7ff000, 0x1000) + 0xcc0; 346f7018c21STomi Valkeinen par->cmap_data = par->cmap_adr + 1; 347f7018c21STomi Valkeinen par->cmap_type = cmap_simple; 348f7018c21STomi Valkeinen } else if (dp && (of_device_is_compatible(dp, "pci1014,b7") || 349f7018c21STomi Valkeinen of_device_is_compatible(dp, "pci1014,21c"))) { 350f7018c21STomi Valkeinen par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000); 351f7018c21STomi Valkeinen if (par->cmap_adr) 352f7018c21STomi Valkeinen par->cmap_type = cmap_gxt2000; 35300257e0cSRob Herring } else if (of_node_name_prefix(dp, "vga,Display-")) { 354f7018c21STomi Valkeinen /* Look for AVIVO initialized by SLOF */ 355f7018c21STomi Valkeinen struct device_node *pciparent = of_get_parent(dp); 356f7018c21STomi Valkeinen const u32 *vid, *did; 357f7018c21STomi Valkeinen vid = of_get_property(pciparent, "vendor-id", NULL); 358f7018c21STomi Valkeinen did = of_get_property(pciparent, "device-id", NULL); 359f7018c21STomi Valkeinen /* This will match most R5xx */ 360f7018c21STomi Valkeinen if (vid && did && *vid == 0x1002 && 361f7018c21STomi Valkeinen ((*did >= 0x7100 && *did < 0x7800) || 362f7018c21STomi Valkeinen (*did >= 0x9400))) { 363f7018c21STomi Valkeinen par->cmap_adr = offb_map_reg(pciparent, 2, 0, 0x10000); 364f7018c21STomi Valkeinen if (par->cmap_adr) 365f7018c21STomi Valkeinen par->cmap_type = cmap_avivo; 366f7018c21STomi Valkeinen } 367f7018c21STomi Valkeinen of_node_put(pciparent); 368f7018c21STomi Valkeinen } else if (dp && of_device_is_compatible(dp, "qemu,std-vga")) { 369f7018c21STomi Valkeinen #ifdef __BIG_ENDIAN 370f7018c21STomi Valkeinen const __be32 io_of_addr[3] = { 0x01000000, 0x0, 0x0 }; 371f7018c21STomi Valkeinen #else 372f7018c21STomi Valkeinen const __be32 io_of_addr[3] = { 0x00000001, 0x0, 0x0 }; 373f7018c21STomi Valkeinen #endif 374f7018c21STomi Valkeinen u64 io_addr = of_translate_address(dp, io_of_addr); 375f7018c21STomi Valkeinen if (io_addr != OF_BAD_ADDR) { 376f7018c21STomi Valkeinen par->cmap_adr = ioremap(io_addr + 0x3c8, 2); 377f7018c21STomi Valkeinen if (par->cmap_adr) { 378f7018c21STomi Valkeinen par->cmap_type = cmap_simple; 379f7018c21STomi Valkeinen par->cmap_data = par->cmap_adr + 1; 380f7018c21STomi Valkeinen } 381f7018c21STomi Valkeinen } 382f7018c21STomi Valkeinen } 383f7018c21STomi Valkeinen info->fix.visual = (par->cmap_type != cmap_unknown) ? 384f7018c21STomi Valkeinen FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; 385f7018c21STomi Valkeinen } 386f7018c21STomi Valkeinen 3876d7e6533SRob Herring static void __init offb_init_fb(const char *name, 388f7018c21STomi Valkeinen int width, int height, int depth, 389f7018c21STomi Valkeinen int pitch, unsigned long address, 390f7018c21STomi Valkeinen int foreign_endian, struct device_node *dp) 391f7018c21STomi Valkeinen { 392f7018c21STomi Valkeinen unsigned long res_size = pitch * height; 393f7018c21STomi Valkeinen struct offb_par *par = &default_par; 394f7018c21STomi Valkeinen unsigned long res_start = address; 395f7018c21STomi Valkeinen struct fb_fix_screeninfo *fix; 396f7018c21STomi Valkeinen struct fb_var_screeninfo *var; 397f7018c21STomi Valkeinen struct fb_info *info; 398f7018c21STomi Valkeinen 399f7018c21STomi Valkeinen if (!request_mem_region(res_start, res_size, "offb")) 400f7018c21STomi Valkeinen return; 401f7018c21STomi Valkeinen 402f7018c21STomi Valkeinen printk(KERN_INFO 403f7018c21STomi Valkeinen "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n", 404f7018c21STomi Valkeinen width, height, name, address, depth, pitch); 405f7018c21STomi Valkeinen if (depth != 8 && depth != 15 && depth != 16 && depth != 32) { 4066d7e6533SRob Herring printk(KERN_ERR "%pOF: can't use depth = %d\n", dp, depth); 407f7018c21STomi Valkeinen release_mem_region(res_start, res_size); 408f7018c21STomi Valkeinen return; 409f7018c21STomi Valkeinen } 410f7018c21STomi Valkeinen 411f7018c21STomi Valkeinen info = framebuffer_alloc(sizeof(u32) * 16, NULL); 412f7018c21STomi Valkeinen 413f7018c21STomi Valkeinen if (info == 0) { 414f7018c21STomi Valkeinen release_mem_region(res_start, res_size); 415f7018c21STomi Valkeinen return; 416f7018c21STomi Valkeinen } 417f7018c21STomi Valkeinen 418f7018c21STomi Valkeinen fix = &info->fix; 419f7018c21STomi Valkeinen var = &info->var; 420f7018c21STomi Valkeinen info->par = par; 421f7018c21STomi Valkeinen 4225c63e407SRob Herring if (name) { 423f7018c21STomi Valkeinen strcpy(fix->id, "OFfb "); 424f7018c21STomi Valkeinen strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb ")); 425f7018c21STomi Valkeinen fix->id[sizeof(fix->id) - 1] = '\0'; 4265c63e407SRob Herring } else 4275c63e407SRob Herring snprintf(fix->id, sizeof(fix->id), "OFfb %pOFn", dp); 4285c63e407SRob Herring 429f7018c21STomi Valkeinen 430f7018c21STomi Valkeinen var->xres = var->xres_virtual = width; 431f7018c21STomi Valkeinen var->yres = var->yres_virtual = height; 432f7018c21STomi Valkeinen fix->line_length = pitch; 433f7018c21STomi Valkeinen 434f7018c21STomi Valkeinen fix->smem_start = address; 435f7018c21STomi Valkeinen fix->smem_len = pitch * height; 436f7018c21STomi Valkeinen fix->type = FB_TYPE_PACKED_PIXELS; 437f7018c21STomi Valkeinen fix->type_aux = 0; 438f7018c21STomi Valkeinen 439f7018c21STomi Valkeinen par->cmap_type = cmap_unknown; 440f7018c21STomi Valkeinen if (depth == 8) 44100257e0cSRob Herring offb_init_palette_hacks(info, dp, address); 442f7018c21STomi Valkeinen else 443f7018c21STomi Valkeinen fix->visual = FB_VISUAL_TRUECOLOR; 444f7018c21STomi Valkeinen 445f7018c21STomi Valkeinen var->xoffset = var->yoffset = 0; 446f7018c21STomi Valkeinen switch (depth) { 447f7018c21STomi Valkeinen case 8: 448f7018c21STomi Valkeinen var->bits_per_pixel = 8; 449f7018c21STomi Valkeinen var->red.offset = 0; 450f7018c21STomi Valkeinen var->red.length = 8; 451f7018c21STomi Valkeinen var->green.offset = 0; 452f7018c21STomi Valkeinen var->green.length = 8; 453f7018c21STomi Valkeinen var->blue.offset = 0; 454f7018c21STomi Valkeinen var->blue.length = 8; 455f7018c21STomi Valkeinen var->transp.offset = 0; 456f7018c21STomi Valkeinen var->transp.length = 0; 457f7018c21STomi Valkeinen break; 458f7018c21STomi Valkeinen case 15: /* RGB 555 */ 459f7018c21STomi Valkeinen var->bits_per_pixel = 16; 460f7018c21STomi Valkeinen var->red.offset = 10; 461f7018c21STomi Valkeinen var->red.length = 5; 462f7018c21STomi Valkeinen var->green.offset = 5; 463f7018c21STomi Valkeinen var->green.length = 5; 464f7018c21STomi Valkeinen var->blue.offset = 0; 465f7018c21STomi Valkeinen var->blue.length = 5; 466f7018c21STomi Valkeinen var->transp.offset = 0; 467f7018c21STomi Valkeinen var->transp.length = 0; 468f7018c21STomi Valkeinen break; 469f7018c21STomi Valkeinen case 16: /* RGB 565 */ 470f7018c21STomi Valkeinen var->bits_per_pixel = 16; 471f7018c21STomi Valkeinen var->red.offset = 11; 472f7018c21STomi Valkeinen var->red.length = 5; 473f7018c21STomi Valkeinen var->green.offset = 5; 474f7018c21STomi Valkeinen var->green.length = 6; 475f7018c21STomi Valkeinen var->blue.offset = 0; 476f7018c21STomi Valkeinen var->blue.length = 5; 477f7018c21STomi Valkeinen var->transp.offset = 0; 478f7018c21STomi Valkeinen var->transp.length = 0; 479f7018c21STomi Valkeinen break; 480f7018c21STomi Valkeinen case 32: /* RGB 888 */ 481f7018c21STomi Valkeinen var->bits_per_pixel = 32; 482f7018c21STomi Valkeinen var->red.offset = 16; 483f7018c21STomi Valkeinen var->red.length = 8; 484f7018c21STomi Valkeinen var->green.offset = 8; 485f7018c21STomi Valkeinen var->green.length = 8; 486f7018c21STomi Valkeinen var->blue.offset = 0; 487f7018c21STomi Valkeinen var->blue.length = 8; 488f7018c21STomi Valkeinen var->transp.offset = 24; 489f7018c21STomi Valkeinen var->transp.length = 8; 490f7018c21STomi Valkeinen break; 491f7018c21STomi Valkeinen } 492f7018c21STomi Valkeinen var->red.msb_right = var->green.msb_right = var->blue.msb_right = 493f7018c21STomi Valkeinen var->transp.msb_right = 0; 494f7018c21STomi Valkeinen var->grayscale = 0; 495f7018c21STomi Valkeinen var->nonstd = 0; 496f7018c21STomi Valkeinen var->activate = 0; 497f7018c21STomi Valkeinen var->height = var->width = -1; 498f7018c21STomi Valkeinen var->pixclock = 10000; 499f7018c21STomi Valkeinen var->left_margin = var->right_margin = 16; 500f7018c21STomi Valkeinen var->upper_margin = var->lower_margin = 16; 501f7018c21STomi Valkeinen var->hsync_len = var->vsync_len = 8; 502f7018c21STomi Valkeinen var->sync = 0; 503f7018c21STomi Valkeinen var->vmode = FB_VMODE_NONINTERLACED; 504f7018c21STomi Valkeinen 505f7018c21STomi Valkeinen /* set offb aperture size for generic probing */ 506f7018c21STomi Valkeinen info->apertures = alloc_apertures(1); 507f7018c21STomi Valkeinen if (!info->apertures) 508f7018c21STomi Valkeinen goto out_aper; 509f7018c21STomi Valkeinen info->apertures->ranges[0].base = address; 510f7018c21STomi Valkeinen info->apertures->ranges[0].size = fix->smem_len; 511f7018c21STomi Valkeinen 512f7018c21STomi Valkeinen info->fbops = &offb_ops; 513f7018c21STomi Valkeinen info->screen_base = ioremap(address, fix->smem_len); 514f7018c21STomi Valkeinen info->pseudo_palette = (void *) (info + 1); 515f7018c21STomi Valkeinen info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE | foreign_endian; 516f7018c21STomi Valkeinen 517f7018c21STomi Valkeinen fb_alloc_cmap(&info->cmap, 256, 0); 518f7018c21STomi Valkeinen 519f7018c21STomi Valkeinen if (register_framebuffer(info) < 0) 520f7018c21STomi Valkeinen goto out_err; 521f7018c21STomi Valkeinen 5226d7e6533SRob Herring fb_info(info, "Open Firmware frame buffer device on %pOF\n", dp); 523f7018c21STomi Valkeinen return; 524f7018c21STomi Valkeinen 525f7018c21STomi Valkeinen out_err: 5269cbaf4d9SMathieu Malaterre fb_dealloc_cmap(&info->cmap); 527f7018c21STomi Valkeinen iounmap(info->screen_base); 528f7018c21STomi Valkeinen out_aper: 529f7018c21STomi Valkeinen iounmap(par->cmap_adr); 530f7018c21STomi Valkeinen par->cmap_adr = NULL; 531f7018c21STomi Valkeinen framebuffer_release(info); 532f7018c21STomi Valkeinen release_mem_region(res_start, res_size); 533f7018c21STomi Valkeinen } 534f7018c21STomi Valkeinen 535f7018c21STomi Valkeinen 536f7018c21STomi Valkeinen static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) 537f7018c21STomi Valkeinen { 538f7018c21STomi Valkeinen unsigned int len; 539f7018c21STomi Valkeinen int i, width = 640, height = 480, depth = 8, pitch = 640; 540f7018c21STomi Valkeinen unsigned int flags, rsize, addr_prop = 0; 541f7018c21STomi Valkeinen unsigned long max_size = 0; 542f7018c21STomi Valkeinen u64 rstart, address = OF_BAD_ADDR; 543f7018c21STomi Valkeinen const __be32 *pp, *addrp, *up; 544f7018c21STomi Valkeinen u64 asize; 545f7018c21STomi Valkeinen int foreign_endian = 0; 546f7018c21STomi Valkeinen 547f7018c21STomi Valkeinen #ifdef __BIG_ENDIAN 548f7018c21STomi Valkeinen if (of_get_property(dp, "little-endian", NULL)) 549f7018c21STomi Valkeinen foreign_endian = FBINFO_FOREIGN_ENDIAN; 550f7018c21STomi Valkeinen #else 551f7018c21STomi Valkeinen if (of_get_property(dp, "big-endian", NULL)) 552f7018c21STomi Valkeinen foreign_endian = FBINFO_FOREIGN_ENDIAN; 553f7018c21STomi Valkeinen #endif 554f7018c21STomi Valkeinen 555f7018c21STomi Valkeinen pp = of_get_property(dp, "linux,bootx-depth", &len); 556f7018c21STomi Valkeinen if (pp == NULL) 557f7018c21STomi Valkeinen pp = of_get_property(dp, "depth", &len); 558f7018c21STomi Valkeinen if (pp && len == sizeof(u32)) 559f7018c21STomi Valkeinen depth = be32_to_cpup(pp); 560f7018c21STomi Valkeinen 561f7018c21STomi Valkeinen pp = of_get_property(dp, "linux,bootx-width", &len); 562f7018c21STomi Valkeinen if (pp == NULL) 563f7018c21STomi Valkeinen pp = of_get_property(dp, "width", &len); 564f7018c21STomi Valkeinen if (pp && len == sizeof(u32)) 565f7018c21STomi Valkeinen width = be32_to_cpup(pp); 566f7018c21STomi Valkeinen 567f7018c21STomi Valkeinen pp = of_get_property(dp, "linux,bootx-height", &len); 568f7018c21STomi Valkeinen if (pp == NULL) 569f7018c21STomi Valkeinen pp = of_get_property(dp, "height", &len); 570f7018c21STomi Valkeinen if (pp && len == sizeof(u32)) 571f7018c21STomi Valkeinen height = be32_to_cpup(pp); 572f7018c21STomi Valkeinen 573f7018c21STomi Valkeinen pp = of_get_property(dp, "linux,bootx-linebytes", &len); 574f7018c21STomi Valkeinen if (pp == NULL) 575f7018c21STomi Valkeinen pp = of_get_property(dp, "linebytes", &len); 576f7018c21STomi Valkeinen if (pp && len == sizeof(u32) && (*pp != 0xffffffffu)) 577f7018c21STomi Valkeinen pitch = be32_to_cpup(pp); 578f7018c21STomi Valkeinen else 579f7018c21STomi Valkeinen pitch = width * ((depth + 7) / 8); 580f7018c21STomi Valkeinen 581f7018c21STomi Valkeinen rsize = (unsigned long)pitch * (unsigned long)height; 582f7018c21STomi Valkeinen 583f7018c21STomi Valkeinen /* Ok, now we try to figure out the address of the framebuffer. 584f7018c21STomi Valkeinen * 585f7018c21STomi Valkeinen * Unfortunately, Open Firmware doesn't provide a standard way to do 586f7018c21STomi Valkeinen * so. All we can do is a dodgy heuristic that happens to work in 587f7018c21STomi Valkeinen * practice. On most machines, the "address" property contains what 588f7018c21STomi Valkeinen * we need, though not on Matrox cards found in IBM machines. What I've 589f7018c21STomi Valkeinen * found that appears to give good results is to go through the PCI 590f7018c21STomi Valkeinen * ranges and pick one that is both big enough and if possible encloses 591f7018c21STomi Valkeinen * the "address" property. If none match, we pick the biggest 592f7018c21STomi Valkeinen */ 593f7018c21STomi Valkeinen up = of_get_property(dp, "linux,bootx-addr", &len); 594f7018c21STomi Valkeinen if (up == NULL) 595f7018c21STomi Valkeinen up = of_get_property(dp, "address", &len); 596f7018c21STomi Valkeinen if (up && len == sizeof(u32)) 597f7018c21STomi Valkeinen addr_prop = *up; 598f7018c21STomi Valkeinen 599f7018c21STomi Valkeinen /* Hack for when BootX is passing us */ 600f7018c21STomi Valkeinen if (no_real_node) 601f7018c21STomi Valkeinen goto skip_addr; 602f7018c21STomi Valkeinen 603f7018c21STomi Valkeinen for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags)) 604f7018c21STomi Valkeinen != NULL; i++) { 605f7018c21STomi Valkeinen int match_addrp = 0; 606f7018c21STomi Valkeinen 607f7018c21STomi Valkeinen if (!(flags & IORESOURCE_MEM)) 608f7018c21STomi Valkeinen continue; 609f7018c21STomi Valkeinen if (asize < rsize) 610f7018c21STomi Valkeinen continue; 611f7018c21STomi Valkeinen rstart = of_translate_address(dp, addrp); 612f7018c21STomi Valkeinen if (rstart == OF_BAD_ADDR) 613f7018c21STomi Valkeinen continue; 614f7018c21STomi Valkeinen if (addr_prop && (rstart <= addr_prop) && 615f7018c21STomi Valkeinen ((rstart + asize) >= (addr_prop + rsize))) 616f7018c21STomi Valkeinen match_addrp = 1; 617f7018c21STomi Valkeinen if (match_addrp) { 618f7018c21STomi Valkeinen address = addr_prop; 619f7018c21STomi Valkeinen break; 620f7018c21STomi Valkeinen } 621f7018c21STomi Valkeinen if (rsize > max_size) { 622f7018c21STomi Valkeinen max_size = rsize; 623f7018c21STomi Valkeinen address = OF_BAD_ADDR; 624f7018c21STomi Valkeinen } 625f7018c21STomi Valkeinen 626f7018c21STomi Valkeinen if (address == OF_BAD_ADDR) 627f7018c21STomi Valkeinen address = rstart; 628f7018c21STomi Valkeinen } 629f7018c21STomi Valkeinen skip_addr: 630f7018c21STomi Valkeinen if (address == OF_BAD_ADDR && addr_prop) 631f7018c21STomi Valkeinen address = (u64)addr_prop; 632f7018c21STomi Valkeinen if (address != OF_BAD_ADDR) { 6335bda8f7bSYongji Xie #ifdef CONFIG_PCI 6345bda8f7bSYongji Xie const __be32 *vidp, *didp; 6355bda8f7bSYongji Xie u32 vid, did; 6365bda8f7bSYongji Xie struct pci_dev *pdev; 6375bda8f7bSYongji Xie 6385bda8f7bSYongji Xie vidp = of_get_property(dp, "vendor-id", NULL); 6395bda8f7bSYongji Xie didp = of_get_property(dp, "device-id", NULL); 6405bda8f7bSYongji Xie if (vidp && didp) { 6415bda8f7bSYongji Xie vid = be32_to_cpup(vidp); 6425bda8f7bSYongji Xie did = be32_to_cpup(didp); 6435bda8f7bSYongji Xie pdev = pci_get_device(vid, did, NULL); 6445bda8f7bSYongji Xie if (!pdev || pci_enable_device(pdev)) 6455bda8f7bSYongji Xie return; 6465bda8f7bSYongji Xie } 6475bda8f7bSYongji Xie #endif 648f7018c21STomi Valkeinen /* kludge for valkyrie */ 649f7018c21STomi Valkeinen if (strcmp(dp->name, "valkyrie") == 0) 650f7018c21STomi Valkeinen address += 0x1000; 6515c63e407SRob Herring offb_init_fb(no_real_node ? "bootx" : NULL, 652f7018c21STomi Valkeinen width, height, depth, pitch, address, 653f7018c21STomi Valkeinen foreign_endian, no_real_node ? NULL : dp); 654f7018c21STomi Valkeinen } 655f7018c21STomi Valkeinen } 656f7018c21STomi Valkeinen 657f7018c21STomi Valkeinen static int __init offb_init(void) 658f7018c21STomi Valkeinen { 659f7018c21STomi Valkeinen struct device_node *dp = NULL, *boot_disp = NULL; 660f7018c21STomi Valkeinen 661f7018c21STomi Valkeinen if (fb_get_options("offb", NULL)) 662f7018c21STomi Valkeinen return -ENODEV; 663f7018c21STomi Valkeinen 664f7018c21STomi Valkeinen /* Check if we have a MacOS display without a node spec */ 665f7018c21STomi Valkeinen if (of_get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) { 666f7018c21STomi Valkeinen /* The old code tried to work out which node was the MacOS 667f7018c21STomi Valkeinen * display based on the address. I'm dropping that since the 668f7018c21STomi Valkeinen * lack of a node spec only happens with old BootX versions 669f7018c21STomi Valkeinen * (users can update) and with this code, they'll still get 670f7018c21STomi Valkeinen * a display (just not the palette hacks). 671f7018c21STomi Valkeinen */ 672f7018c21STomi Valkeinen offb_init_nodriver(of_chosen, 1); 673f7018c21STomi Valkeinen } 674f7018c21STomi Valkeinen 6758d225568SDmitry Torokhov for_each_node_by_type(dp, "display") { 676f7018c21STomi Valkeinen if (of_get_property(dp, "linux,opened", NULL) && 677f7018c21STomi Valkeinen of_get_property(dp, "linux,boot-display", NULL)) { 678f7018c21STomi Valkeinen boot_disp = dp; 679f7018c21STomi Valkeinen offb_init_nodriver(dp, 0); 680f7018c21STomi Valkeinen } 681f7018c21STomi Valkeinen } 6828d225568SDmitry Torokhov for_each_node_by_type(dp, "display") { 683f7018c21STomi Valkeinen if (of_get_property(dp, "linux,opened", NULL) && 684f7018c21STomi Valkeinen dp != boot_disp) 685f7018c21STomi Valkeinen offb_init_nodriver(dp, 0); 686f7018c21STomi Valkeinen } 687f7018c21STomi Valkeinen 688f7018c21STomi Valkeinen return 0; 689f7018c21STomi Valkeinen } 690f7018c21STomi Valkeinen 691f7018c21STomi Valkeinen 692f7018c21STomi Valkeinen module_init(offb_init); 693f7018c21STomi Valkeinen MODULE_LICENSE("GPL"); 694