18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/video/offb.c -- Open Firmware based frame buffer device 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 1997 Geert Uytterhoeven 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This driver is partly based on the PowerMac console driver: 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 1996 Paul Mackerras 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 118c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 128c2ecf20Sopenharmony_ci * more details. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/errno.h> 188c2ecf20Sopenharmony_ci#include <linux/string.h> 198c2ecf20Sopenharmony_ci#include <linux/mm.h> 208c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <linux/of_address.h> 248c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 258c2ecf20Sopenharmony_ci#include <linux/fb.h> 268c2ecf20Sopenharmony_ci#include <linux/init.h> 278c2ecf20Sopenharmony_ci#include <linux/ioport.h> 288c2ecf20Sopenharmony_ci#include <linux/pci.h> 298c2ecf20Sopenharmony_ci#include <asm/io.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC32 328c2ecf20Sopenharmony_ci#include <asm/bootx.h> 338c2ecf20Sopenharmony_ci#endif 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "macmodes.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Supported palette hacks */ 388c2ecf20Sopenharmony_cienum { 398c2ecf20Sopenharmony_ci cmap_unknown, 408c2ecf20Sopenharmony_ci cmap_simple, /* ATI Mach64 */ 418c2ecf20Sopenharmony_ci cmap_r128, /* ATI Rage128 */ 428c2ecf20Sopenharmony_ci cmap_M3A, /* ATI Rage Mobility M3 Head A */ 438c2ecf20Sopenharmony_ci cmap_M3B, /* ATI Rage Mobility M3 Head B */ 448c2ecf20Sopenharmony_ci cmap_radeon, /* ATI Radeon */ 458c2ecf20Sopenharmony_ci cmap_gxt2000, /* IBM GXT2000 */ 468c2ecf20Sopenharmony_ci cmap_avivo, /* ATI R5xx */ 478c2ecf20Sopenharmony_ci cmap_qemu, /* qemu vga */ 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct offb_par { 518c2ecf20Sopenharmony_ci volatile void __iomem *cmap_adr; 528c2ecf20Sopenharmony_ci volatile void __iomem *cmap_data; 538c2ecf20Sopenharmony_ci int cmap_type; 548c2ecf20Sopenharmony_ci int blanked; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct offb_par default_par; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC32 608c2ecf20Sopenharmony_ciextern boot_infos_t *boot_infos; 618c2ecf20Sopenharmony_ci#endif 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* Definitions used by the Avivo palette hack */ 648c2ecf20Sopenharmony_ci#define AVIVO_DC_LUT_RW_SELECT 0x6480 658c2ecf20Sopenharmony_ci#define AVIVO_DC_LUT_RW_MODE 0x6484 668c2ecf20Sopenharmony_ci#define AVIVO_DC_LUT_RW_INDEX 0x6488 678c2ecf20Sopenharmony_ci#define AVIVO_DC_LUT_SEQ_COLOR 0x648c 688c2ecf20Sopenharmony_ci#define AVIVO_DC_LUT_PWL_DATA 0x6490 698c2ecf20Sopenharmony_ci#define AVIVO_DC_LUT_30_COLOR 0x6494 708c2ecf20Sopenharmony_ci#define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498 718c2ecf20Sopenharmony_ci#define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c 728c2ecf20Sopenharmony_ci#define AVIVO_DC_LUT_AUTOFILL 0x64a0 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTA_CONTROL 0x64c0 758c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4 768c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8 778c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc 788c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0 798c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 808c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTB_CONTROL 0x6cc0 838c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4 848c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8 858c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc 868c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0 878c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4 888c2ecf20Sopenharmony_ci#define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* 918c2ecf20Sopenharmony_ci * Set a single color register. The values supplied are already 928c2ecf20Sopenharmony_ci * rounded down to the hardware's capabilities (according to the 938c2ecf20Sopenharmony_ci * entries in the var structure). Return != 0 for invalid regno. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 978c2ecf20Sopenharmony_ci u_int transp, struct fb_info *info) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct offb_par *par = (struct offb_par *) info->par; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 1028c2ecf20Sopenharmony_ci u32 *pal = info->pseudo_palette; 1038c2ecf20Sopenharmony_ci u32 cr = red >> (16 - info->var.red.length); 1048c2ecf20Sopenharmony_ci u32 cg = green >> (16 - info->var.green.length); 1058c2ecf20Sopenharmony_ci u32 cb = blue >> (16 - info->var.blue.length); 1068c2ecf20Sopenharmony_ci u32 value; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (regno >= 16) 1098c2ecf20Sopenharmony_ci return -EINVAL; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci value = (cr << info->var.red.offset) | 1128c2ecf20Sopenharmony_ci (cg << info->var.green.offset) | 1138c2ecf20Sopenharmony_ci (cb << info->var.blue.offset); 1148c2ecf20Sopenharmony_ci if (info->var.transp.length > 0) { 1158c2ecf20Sopenharmony_ci u32 mask = (1 << info->var.transp.length) - 1; 1168c2ecf20Sopenharmony_ci mask <<= info->var.transp.offset; 1178c2ecf20Sopenharmony_ci value |= mask; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci pal[regno] = value; 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (regno > 255) 1248c2ecf20Sopenharmony_ci return -EINVAL; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci red >>= 8; 1278c2ecf20Sopenharmony_ci green >>= 8; 1288c2ecf20Sopenharmony_ci blue >>= 8; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (!par->cmap_adr) 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci switch (par->cmap_type) { 1348c2ecf20Sopenharmony_ci case cmap_simple: 1358c2ecf20Sopenharmony_ci writeb(regno, par->cmap_adr); 1368c2ecf20Sopenharmony_ci writeb(red, par->cmap_data); 1378c2ecf20Sopenharmony_ci writeb(green, par->cmap_data); 1388c2ecf20Sopenharmony_ci writeb(blue, par->cmap_data); 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci case cmap_M3A: 1418c2ecf20Sopenharmony_ci /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ 1428c2ecf20Sopenharmony_ci out_le32(par->cmap_adr + 0x58, 1438c2ecf20Sopenharmony_ci in_le32(par->cmap_adr + 0x58) & ~0x20); 1448c2ecf20Sopenharmony_ci fallthrough; 1458c2ecf20Sopenharmony_ci case cmap_r128: 1468c2ecf20Sopenharmony_ci /* Set palette index & data */ 1478c2ecf20Sopenharmony_ci out_8(par->cmap_adr + 0xb0, regno); 1488c2ecf20Sopenharmony_ci out_le32(par->cmap_adr + 0xb4, 1498c2ecf20Sopenharmony_ci (red << 16 | green << 8 | blue)); 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci case cmap_M3B: 1528c2ecf20Sopenharmony_ci /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ 1538c2ecf20Sopenharmony_ci out_le32(par->cmap_adr + 0x58, 1548c2ecf20Sopenharmony_ci in_le32(par->cmap_adr + 0x58) | 0x20); 1558c2ecf20Sopenharmony_ci /* Set palette index & data */ 1568c2ecf20Sopenharmony_ci out_8(par->cmap_adr + 0xb0, regno); 1578c2ecf20Sopenharmony_ci out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue)); 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci case cmap_radeon: 1608c2ecf20Sopenharmony_ci /* Set palette index & data (could be smarter) */ 1618c2ecf20Sopenharmony_ci out_8(par->cmap_adr + 0xb0, regno); 1628c2ecf20Sopenharmony_ci out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue)); 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci case cmap_gxt2000: 1658c2ecf20Sopenharmony_ci out_le32(((unsigned __iomem *) par->cmap_adr) + regno, 1668c2ecf20Sopenharmony_ci (red << 16 | green << 8 | blue)); 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci case cmap_avivo: 1698c2ecf20Sopenharmony_ci /* Write to both LUTs for now */ 1708c2ecf20Sopenharmony_ci writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 1718c2ecf20Sopenharmony_ci writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 1728c2ecf20Sopenharmony_ci writel(((red) << 22) | ((green) << 12) | ((blue) << 2), 1738c2ecf20Sopenharmony_ci par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 1748c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 1758c2ecf20Sopenharmony_ci writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 1768c2ecf20Sopenharmony_ci writel(((red) << 22) | ((green) << 12) | ((blue) << 2), 1778c2ecf20Sopenharmony_ci par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* 1858c2ecf20Sopenharmony_ci * Blank the display. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int offb_blank(int blank, struct fb_info *info) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct offb_par *par = (struct offb_par *) info->par; 1918c2ecf20Sopenharmony_ci int i, j; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (!par->cmap_adr) 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (!par->blanked) 1978c2ecf20Sopenharmony_ci if (!blank) 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci par->blanked = blank; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (blank) 2038c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 2048c2ecf20Sopenharmony_ci switch (par->cmap_type) { 2058c2ecf20Sopenharmony_ci case cmap_simple: 2068c2ecf20Sopenharmony_ci writeb(i, par->cmap_adr); 2078c2ecf20Sopenharmony_ci for (j = 0; j < 3; j++) 2088c2ecf20Sopenharmony_ci writeb(0, par->cmap_data); 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci case cmap_M3A: 2118c2ecf20Sopenharmony_ci /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ 2128c2ecf20Sopenharmony_ci out_le32(par->cmap_adr + 0x58, 2138c2ecf20Sopenharmony_ci in_le32(par->cmap_adr + 0x58) & ~0x20); 2148c2ecf20Sopenharmony_ci fallthrough; 2158c2ecf20Sopenharmony_ci case cmap_r128: 2168c2ecf20Sopenharmony_ci /* Set palette index & data */ 2178c2ecf20Sopenharmony_ci out_8(par->cmap_adr + 0xb0, i); 2188c2ecf20Sopenharmony_ci out_le32(par->cmap_adr + 0xb4, 0); 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci case cmap_M3B: 2218c2ecf20Sopenharmony_ci /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ 2228c2ecf20Sopenharmony_ci out_le32(par->cmap_adr + 0x58, 2238c2ecf20Sopenharmony_ci in_le32(par->cmap_adr + 0x58) | 0x20); 2248c2ecf20Sopenharmony_ci /* Set palette index & data */ 2258c2ecf20Sopenharmony_ci out_8(par->cmap_adr + 0xb0, i); 2268c2ecf20Sopenharmony_ci out_le32(par->cmap_adr + 0xb4, 0); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci case cmap_radeon: 2298c2ecf20Sopenharmony_ci out_8(par->cmap_adr + 0xb0, i); 2308c2ecf20Sopenharmony_ci out_le32(par->cmap_adr + 0xb4, 0); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci case cmap_gxt2000: 2338c2ecf20Sopenharmony_ci out_le32(((unsigned __iomem *) par->cmap_adr) + i, 2348c2ecf20Sopenharmony_ci 0); 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci case cmap_avivo: 2378c2ecf20Sopenharmony_ci writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 2388c2ecf20Sopenharmony_ci writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 2398c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 2408c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 2418c2ecf20Sopenharmony_ci writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); 2428c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR); 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci } else 2468c2ecf20Sopenharmony_ci fb_set_cmap(&info->cmap, info); 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int offb_set_par(struct fb_info *info) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct offb_par *par = (struct offb_par *) info->par; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* On avivo, initialize palette control */ 2558c2ecf20Sopenharmony_ci if (par->cmap_type == cmap_avivo) { 2568c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUTA_CONTROL); 2578c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_BLUE); 2588c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_GREEN); 2598c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_RED); 2608c2ecf20Sopenharmony_ci writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_BLUE); 2618c2ecf20Sopenharmony_ci writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_GREEN); 2628c2ecf20Sopenharmony_ci writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_RED); 2638c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUTB_CONTROL); 2648c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_BLUE); 2658c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_GREEN); 2668c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_RED); 2678c2ecf20Sopenharmony_ci writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_BLUE); 2688c2ecf20Sopenharmony_ci writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_GREEN); 2698c2ecf20Sopenharmony_ci writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_RED); 2708c2ecf20Sopenharmony_ci writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 2718c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE); 2728c2ecf20Sopenharmony_ci writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK); 2738c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); 2748c2ecf20Sopenharmony_ci writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE); 2758c2ecf20Sopenharmony_ci writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic void offb_destroy(struct fb_info *info) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci if (info->screen_base) 2838c2ecf20Sopenharmony_ci iounmap(info->screen_base); 2848c2ecf20Sopenharmony_ci release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); 2858c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 2868c2ecf20Sopenharmony_ci framebuffer_release(info); 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic const struct fb_ops offb_ops = { 2908c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2918c2ecf20Sopenharmony_ci .fb_destroy = offb_destroy, 2928c2ecf20Sopenharmony_ci .fb_setcolreg = offb_setcolreg, 2938c2ecf20Sopenharmony_ci .fb_set_par = offb_set_par, 2948c2ecf20Sopenharmony_ci .fb_blank = offb_blank, 2958c2ecf20Sopenharmony_ci .fb_fillrect = cfb_fillrect, 2968c2ecf20Sopenharmony_ci .fb_copyarea = cfb_copyarea, 2978c2ecf20Sopenharmony_ci .fb_imageblit = cfb_imageblit, 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic void __iomem *offb_map_reg(struct device_node *np, int index, 3018c2ecf20Sopenharmony_ci unsigned long offset, unsigned long size) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci const __be32 *addrp; 3048c2ecf20Sopenharmony_ci u64 asize, taddr; 3058c2ecf20Sopenharmony_ci unsigned int flags; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci addrp = of_get_pci_address(np, index, &asize, &flags); 3088c2ecf20Sopenharmony_ci if (addrp == NULL) 3098c2ecf20Sopenharmony_ci addrp = of_get_address(np, index, &asize, &flags); 3108c2ecf20Sopenharmony_ci if (addrp == NULL) 3118c2ecf20Sopenharmony_ci return NULL; 3128c2ecf20Sopenharmony_ci if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) 3138c2ecf20Sopenharmony_ci return NULL; 3148c2ecf20Sopenharmony_ci if ((offset + size) > asize) 3158c2ecf20Sopenharmony_ci return NULL; 3168c2ecf20Sopenharmony_ci taddr = of_translate_address(np, addrp); 3178c2ecf20Sopenharmony_ci if (taddr == OF_BAD_ADDR) 3188c2ecf20Sopenharmony_ci return NULL; 3198c2ecf20Sopenharmony_ci return ioremap(taddr + offset, size); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp, 3238c2ecf20Sopenharmony_ci unsigned long address) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct offb_par *par = (struct offb_par *) info->par; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (of_node_name_prefix(dp, "ATY,Rage128")) { 3288c2ecf20Sopenharmony_ci par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); 3298c2ecf20Sopenharmony_ci if (par->cmap_adr) 3308c2ecf20Sopenharmony_ci par->cmap_type = cmap_r128; 3318c2ecf20Sopenharmony_ci } else if (of_node_name_prefix(dp, "ATY,RageM3pA") || 3328c2ecf20Sopenharmony_ci of_node_name_prefix(dp, "ATY,RageM3p12A")) { 3338c2ecf20Sopenharmony_ci par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); 3348c2ecf20Sopenharmony_ci if (par->cmap_adr) 3358c2ecf20Sopenharmony_ci par->cmap_type = cmap_M3A; 3368c2ecf20Sopenharmony_ci } else if (of_node_name_prefix(dp, "ATY,RageM3pB")) { 3378c2ecf20Sopenharmony_ci par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); 3388c2ecf20Sopenharmony_ci if (par->cmap_adr) 3398c2ecf20Sopenharmony_ci par->cmap_type = cmap_M3B; 3408c2ecf20Sopenharmony_ci } else if (of_node_name_prefix(dp, "ATY,Rage6")) { 3418c2ecf20Sopenharmony_ci par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff); 3428c2ecf20Sopenharmony_ci if (par->cmap_adr) 3438c2ecf20Sopenharmony_ci par->cmap_type = cmap_radeon; 3448c2ecf20Sopenharmony_ci } else if (of_node_name_prefix(dp, "ATY,")) { 3458c2ecf20Sopenharmony_ci unsigned long base = address & 0xff000000UL; 3468c2ecf20Sopenharmony_ci par->cmap_adr = 3478c2ecf20Sopenharmony_ci ioremap(base + 0x7ff000, 0x1000) + 0xcc0; 3488c2ecf20Sopenharmony_ci par->cmap_data = par->cmap_adr + 1; 3498c2ecf20Sopenharmony_ci par->cmap_type = cmap_simple; 3508c2ecf20Sopenharmony_ci } else if (dp && (of_device_is_compatible(dp, "pci1014,b7") || 3518c2ecf20Sopenharmony_ci of_device_is_compatible(dp, "pci1014,21c"))) { 3528c2ecf20Sopenharmony_ci par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000); 3538c2ecf20Sopenharmony_ci if (par->cmap_adr) 3548c2ecf20Sopenharmony_ci par->cmap_type = cmap_gxt2000; 3558c2ecf20Sopenharmony_ci } else if (of_node_name_prefix(dp, "vga,Display-")) { 3568c2ecf20Sopenharmony_ci /* Look for AVIVO initialized by SLOF */ 3578c2ecf20Sopenharmony_ci struct device_node *pciparent = of_get_parent(dp); 3588c2ecf20Sopenharmony_ci const u32 *vid, *did; 3598c2ecf20Sopenharmony_ci vid = of_get_property(pciparent, "vendor-id", NULL); 3608c2ecf20Sopenharmony_ci did = of_get_property(pciparent, "device-id", NULL); 3618c2ecf20Sopenharmony_ci /* This will match most R5xx */ 3628c2ecf20Sopenharmony_ci if (vid && did && *vid == 0x1002 && 3638c2ecf20Sopenharmony_ci ((*did >= 0x7100 && *did < 0x7800) || 3648c2ecf20Sopenharmony_ci (*did >= 0x9400))) { 3658c2ecf20Sopenharmony_ci par->cmap_adr = offb_map_reg(pciparent, 2, 0, 0x10000); 3668c2ecf20Sopenharmony_ci if (par->cmap_adr) 3678c2ecf20Sopenharmony_ci par->cmap_type = cmap_avivo; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci of_node_put(pciparent); 3708c2ecf20Sopenharmony_ci } else if (dp && of_device_is_compatible(dp, "qemu,std-vga")) { 3718c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 3728c2ecf20Sopenharmony_ci const __be32 io_of_addr[3] = { 0x01000000, 0x0, 0x0 }; 3738c2ecf20Sopenharmony_ci#else 3748c2ecf20Sopenharmony_ci const __be32 io_of_addr[3] = { 0x00000001, 0x0, 0x0 }; 3758c2ecf20Sopenharmony_ci#endif 3768c2ecf20Sopenharmony_ci u64 io_addr = of_translate_address(dp, io_of_addr); 3778c2ecf20Sopenharmony_ci if (io_addr != OF_BAD_ADDR) { 3788c2ecf20Sopenharmony_ci par->cmap_adr = ioremap(io_addr + 0x3c8, 2); 3798c2ecf20Sopenharmony_ci if (par->cmap_adr) { 3808c2ecf20Sopenharmony_ci par->cmap_type = cmap_simple; 3818c2ecf20Sopenharmony_ci par->cmap_data = par->cmap_adr + 1; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci info->fix.visual = (par->cmap_type != cmap_unknown) ? 3868c2ecf20Sopenharmony_ci FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic void __init offb_init_fb(const char *name, 3908c2ecf20Sopenharmony_ci int width, int height, int depth, 3918c2ecf20Sopenharmony_ci int pitch, unsigned long address, 3928c2ecf20Sopenharmony_ci int foreign_endian, struct device_node *dp) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci unsigned long res_size = pitch * height; 3958c2ecf20Sopenharmony_ci struct offb_par *par = &default_par; 3968c2ecf20Sopenharmony_ci unsigned long res_start = address; 3978c2ecf20Sopenharmony_ci struct fb_fix_screeninfo *fix; 3988c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var; 3998c2ecf20Sopenharmony_ci struct fb_info *info; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (!request_mem_region(res_start, res_size, "offb")) 4028c2ecf20Sopenharmony_ci return; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci printk(KERN_INFO 4058c2ecf20Sopenharmony_ci "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n", 4068c2ecf20Sopenharmony_ci width, height, name, address, depth, pitch); 4078c2ecf20Sopenharmony_ci if (depth != 8 && depth != 15 && depth != 16 && depth != 32) { 4088c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: can't use depth = %d\n", dp, depth); 4098c2ecf20Sopenharmony_ci release_mem_region(res_start, res_size); 4108c2ecf20Sopenharmony_ci return; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(u32) * 16, NULL); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (info == 0) { 4168c2ecf20Sopenharmony_ci release_mem_region(res_start, res_size); 4178c2ecf20Sopenharmony_ci return; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci fix = &info->fix; 4218c2ecf20Sopenharmony_ci var = &info->var; 4228c2ecf20Sopenharmony_ci info->par = par; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (name) { 4258c2ecf20Sopenharmony_ci strcpy(fix->id, "OFfb "); 4268c2ecf20Sopenharmony_ci strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb ")); 4278c2ecf20Sopenharmony_ci fix->id[sizeof(fix->id) - 1] = '\0'; 4288c2ecf20Sopenharmony_ci } else 4298c2ecf20Sopenharmony_ci snprintf(fix->id, sizeof(fix->id), "OFfb %pOFn", dp); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci var->xres = var->xres_virtual = width; 4338c2ecf20Sopenharmony_ci var->yres = var->yres_virtual = height; 4348c2ecf20Sopenharmony_ci fix->line_length = pitch; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci fix->smem_start = address; 4378c2ecf20Sopenharmony_ci fix->smem_len = pitch * height; 4388c2ecf20Sopenharmony_ci fix->type = FB_TYPE_PACKED_PIXELS; 4398c2ecf20Sopenharmony_ci fix->type_aux = 0; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci par->cmap_type = cmap_unknown; 4428c2ecf20Sopenharmony_ci if (depth == 8) 4438c2ecf20Sopenharmony_ci offb_init_palette_hacks(info, dp, address); 4448c2ecf20Sopenharmony_ci else 4458c2ecf20Sopenharmony_ci fix->visual = FB_VISUAL_TRUECOLOR; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci var->xoffset = var->yoffset = 0; 4488c2ecf20Sopenharmony_ci switch (depth) { 4498c2ecf20Sopenharmony_ci case 8: 4508c2ecf20Sopenharmony_ci var->bits_per_pixel = 8; 4518c2ecf20Sopenharmony_ci var->red.offset = 0; 4528c2ecf20Sopenharmony_ci var->red.length = 8; 4538c2ecf20Sopenharmony_ci var->green.offset = 0; 4548c2ecf20Sopenharmony_ci var->green.length = 8; 4558c2ecf20Sopenharmony_ci var->blue.offset = 0; 4568c2ecf20Sopenharmony_ci var->blue.length = 8; 4578c2ecf20Sopenharmony_ci var->transp.offset = 0; 4588c2ecf20Sopenharmony_ci var->transp.length = 0; 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci case 15: /* RGB 555 */ 4618c2ecf20Sopenharmony_ci var->bits_per_pixel = 16; 4628c2ecf20Sopenharmony_ci var->red.offset = 10; 4638c2ecf20Sopenharmony_ci var->red.length = 5; 4648c2ecf20Sopenharmony_ci var->green.offset = 5; 4658c2ecf20Sopenharmony_ci var->green.length = 5; 4668c2ecf20Sopenharmony_ci var->blue.offset = 0; 4678c2ecf20Sopenharmony_ci var->blue.length = 5; 4688c2ecf20Sopenharmony_ci var->transp.offset = 0; 4698c2ecf20Sopenharmony_ci var->transp.length = 0; 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci case 16: /* RGB 565 */ 4728c2ecf20Sopenharmony_ci var->bits_per_pixel = 16; 4738c2ecf20Sopenharmony_ci var->red.offset = 11; 4748c2ecf20Sopenharmony_ci var->red.length = 5; 4758c2ecf20Sopenharmony_ci var->green.offset = 5; 4768c2ecf20Sopenharmony_ci var->green.length = 6; 4778c2ecf20Sopenharmony_ci var->blue.offset = 0; 4788c2ecf20Sopenharmony_ci var->blue.length = 5; 4798c2ecf20Sopenharmony_ci var->transp.offset = 0; 4808c2ecf20Sopenharmony_ci var->transp.length = 0; 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci case 32: /* RGB 888 */ 4838c2ecf20Sopenharmony_ci var->bits_per_pixel = 32; 4848c2ecf20Sopenharmony_ci var->red.offset = 16; 4858c2ecf20Sopenharmony_ci var->red.length = 8; 4868c2ecf20Sopenharmony_ci var->green.offset = 8; 4878c2ecf20Sopenharmony_ci var->green.length = 8; 4888c2ecf20Sopenharmony_ci var->blue.offset = 0; 4898c2ecf20Sopenharmony_ci var->blue.length = 8; 4908c2ecf20Sopenharmony_ci var->transp.offset = 24; 4918c2ecf20Sopenharmony_ci var->transp.length = 8; 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci var->red.msb_right = var->green.msb_right = var->blue.msb_right = 4958c2ecf20Sopenharmony_ci var->transp.msb_right = 0; 4968c2ecf20Sopenharmony_ci var->grayscale = 0; 4978c2ecf20Sopenharmony_ci var->nonstd = 0; 4988c2ecf20Sopenharmony_ci var->activate = 0; 4998c2ecf20Sopenharmony_ci var->height = var->width = -1; 5008c2ecf20Sopenharmony_ci var->pixclock = 10000; 5018c2ecf20Sopenharmony_ci var->left_margin = var->right_margin = 16; 5028c2ecf20Sopenharmony_ci var->upper_margin = var->lower_margin = 16; 5038c2ecf20Sopenharmony_ci var->hsync_len = var->vsync_len = 8; 5048c2ecf20Sopenharmony_ci var->sync = 0; 5058c2ecf20Sopenharmony_ci var->vmode = FB_VMODE_NONINTERLACED; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* set offb aperture size for generic probing */ 5088c2ecf20Sopenharmony_ci info->apertures = alloc_apertures(1); 5098c2ecf20Sopenharmony_ci if (!info->apertures) 5108c2ecf20Sopenharmony_ci goto out_aper; 5118c2ecf20Sopenharmony_ci info->apertures->ranges[0].base = address; 5128c2ecf20Sopenharmony_ci info->apertures->ranges[0].size = fix->smem_len; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci info->fbops = &offb_ops; 5158c2ecf20Sopenharmony_ci info->screen_base = ioremap(address, fix->smem_len); 5168c2ecf20Sopenharmony_ci info->pseudo_palette = (void *) (info + 1); 5178c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE | foreign_endian; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci fb_alloc_cmap(&info->cmap, 256, 0); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (register_framebuffer(info) < 0) 5228c2ecf20Sopenharmony_ci goto out_err; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci fb_info(info, "Open Firmware frame buffer device on %pOF\n", dp); 5258c2ecf20Sopenharmony_ci return; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ciout_err: 5288c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 5298c2ecf20Sopenharmony_ci iounmap(info->screen_base); 5308c2ecf20Sopenharmony_ciout_aper: 5318c2ecf20Sopenharmony_ci iounmap(par->cmap_adr); 5328c2ecf20Sopenharmony_ci par->cmap_adr = NULL; 5338c2ecf20Sopenharmony_ci framebuffer_release(info); 5348c2ecf20Sopenharmony_ci release_mem_region(res_start, res_size); 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic void __init offb_init_nodriver(struct device_node *dp, int no_real_node) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci unsigned int len; 5418c2ecf20Sopenharmony_ci int i, width = 640, height = 480, depth = 8, pitch = 640; 5428c2ecf20Sopenharmony_ci unsigned int flags, rsize, addr_prop = 0; 5438c2ecf20Sopenharmony_ci unsigned long max_size = 0; 5448c2ecf20Sopenharmony_ci u64 rstart, address = OF_BAD_ADDR; 5458c2ecf20Sopenharmony_ci const __be32 *pp, *addrp, *up; 5468c2ecf20Sopenharmony_ci u64 asize; 5478c2ecf20Sopenharmony_ci int foreign_endian = 0; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 5508c2ecf20Sopenharmony_ci if (of_get_property(dp, "little-endian", NULL)) 5518c2ecf20Sopenharmony_ci foreign_endian = FBINFO_FOREIGN_ENDIAN; 5528c2ecf20Sopenharmony_ci#else 5538c2ecf20Sopenharmony_ci if (of_get_property(dp, "big-endian", NULL)) 5548c2ecf20Sopenharmony_ci foreign_endian = FBINFO_FOREIGN_ENDIAN; 5558c2ecf20Sopenharmony_ci#endif 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci pp = of_get_property(dp, "linux,bootx-depth", &len); 5588c2ecf20Sopenharmony_ci if (pp == NULL) 5598c2ecf20Sopenharmony_ci pp = of_get_property(dp, "depth", &len); 5608c2ecf20Sopenharmony_ci if (pp && len == sizeof(u32)) 5618c2ecf20Sopenharmony_ci depth = be32_to_cpup(pp); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci pp = of_get_property(dp, "linux,bootx-width", &len); 5648c2ecf20Sopenharmony_ci if (pp == NULL) 5658c2ecf20Sopenharmony_ci pp = of_get_property(dp, "width", &len); 5668c2ecf20Sopenharmony_ci if (pp && len == sizeof(u32)) 5678c2ecf20Sopenharmony_ci width = be32_to_cpup(pp); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci pp = of_get_property(dp, "linux,bootx-height", &len); 5708c2ecf20Sopenharmony_ci if (pp == NULL) 5718c2ecf20Sopenharmony_ci pp = of_get_property(dp, "height", &len); 5728c2ecf20Sopenharmony_ci if (pp && len == sizeof(u32)) 5738c2ecf20Sopenharmony_ci height = be32_to_cpup(pp); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci pp = of_get_property(dp, "linux,bootx-linebytes", &len); 5768c2ecf20Sopenharmony_ci if (pp == NULL) 5778c2ecf20Sopenharmony_ci pp = of_get_property(dp, "linebytes", &len); 5788c2ecf20Sopenharmony_ci if (pp && len == sizeof(u32) && (*pp != 0xffffffffu)) 5798c2ecf20Sopenharmony_ci pitch = be32_to_cpup(pp); 5808c2ecf20Sopenharmony_ci else 5818c2ecf20Sopenharmony_ci pitch = width * ((depth + 7) / 8); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci rsize = (unsigned long)pitch * (unsigned long)height; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* Ok, now we try to figure out the address of the framebuffer. 5868c2ecf20Sopenharmony_ci * 5878c2ecf20Sopenharmony_ci * Unfortunately, Open Firmware doesn't provide a standard way to do 5888c2ecf20Sopenharmony_ci * so. All we can do is a dodgy heuristic that happens to work in 5898c2ecf20Sopenharmony_ci * practice. On most machines, the "address" property contains what 5908c2ecf20Sopenharmony_ci * we need, though not on Matrox cards found in IBM machines. What I've 5918c2ecf20Sopenharmony_ci * found that appears to give good results is to go through the PCI 5928c2ecf20Sopenharmony_ci * ranges and pick one that is both big enough and if possible encloses 5938c2ecf20Sopenharmony_ci * the "address" property. If none match, we pick the biggest 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_ci up = of_get_property(dp, "linux,bootx-addr", &len); 5968c2ecf20Sopenharmony_ci if (up == NULL) 5978c2ecf20Sopenharmony_ci up = of_get_property(dp, "address", &len); 5988c2ecf20Sopenharmony_ci if (up && len == sizeof(u32)) 5998c2ecf20Sopenharmony_ci addr_prop = *up; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* Hack for when BootX is passing us */ 6028c2ecf20Sopenharmony_ci if (no_real_node) 6038c2ecf20Sopenharmony_ci goto skip_addr; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags)) 6068c2ecf20Sopenharmony_ci != NULL; i++) { 6078c2ecf20Sopenharmony_ci int match_addrp = 0; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (!(flags & IORESOURCE_MEM)) 6108c2ecf20Sopenharmony_ci continue; 6118c2ecf20Sopenharmony_ci if (asize < rsize) 6128c2ecf20Sopenharmony_ci continue; 6138c2ecf20Sopenharmony_ci rstart = of_translate_address(dp, addrp); 6148c2ecf20Sopenharmony_ci if (rstart == OF_BAD_ADDR) 6158c2ecf20Sopenharmony_ci continue; 6168c2ecf20Sopenharmony_ci if (addr_prop && (rstart <= addr_prop) && 6178c2ecf20Sopenharmony_ci ((rstart + asize) >= (addr_prop + rsize))) 6188c2ecf20Sopenharmony_ci match_addrp = 1; 6198c2ecf20Sopenharmony_ci if (match_addrp) { 6208c2ecf20Sopenharmony_ci address = addr_prop; 6218c2ecf20Sopenharmony_ci break; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci if (rsize > max_size) { 6248c2ecf20Sopenharmony_ci max_size = rsize; 6258c2ecf20Sopenharmony_ci address = OF_BAD_ADDR; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (address == OF_BAD_ADDR) 6298c2ecf20Sopenharmony_ci address = rstart; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci skip_addr: 6328c2ecf20Sopenharmony_ci if (address == OF_BAD_ADDR && addr_prop) 6338c2ecf20Sopenharmony_ci address = (u64)addr_prop; 6348c2ecf20Sopenharmony_ci if (address != OF_BAD_ADDR) { 6358c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 6368c2ecf20Sopenharmony_ci const __be32 *vidp, *didp; 6378c2ecf20Sopenharmony_ci u32 vid, did; 6388c2ecf20Sopenharmony_ci struct pci_dev *pdev; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci vidp = of_get_property(dp, "vendor-id", NULL); 6418c2ecf20Sopenharmony_ci didp = of_get_property(dp, "device-id", NULL); 6428c2ecf20Sopenharmony_ci if (vidp && didp) { 6438c2ecf20Sopenharmony_ci vid = be32_to_cpup(vidp); 6448c2ecf20Sopenharmony_ci did = be32_to_cpup(didp); 6458c2ecf20Sopenharmony_ci pdev = pci_get_device(vid, did, NULL); 6468c2ecf20Sopenharmony_ci if (!pdev || pci_enable_device(pdev)) 6478c2ecf20Sopenharmony_ci return; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci#endif 6508c2ecf20Sopenharmony_ci /* kludge for valkyrie */ 6518c2ecf20Sopenharmony_ci if (of_node_name_eq(dp, "valkyrie")) 6528c2ecf20Sopenharmony_ci address += 0x1000; 6538c2ecf20Sopenharmony_ci offb_init_fb(no_real_node ? "bootx" : NULL, 6548c2ecf20Sopenharmony_ci width, height, depth, pitch, address, 6558c2ecf20Sopenharmony_ci foreign_endian, no_real_node ? NULL : dp); 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic int __init offb_init(void) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci struct device_node *dp = NULL, *boot_disp = NULL; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (fb_get_options("offb", NULL)) 6648c2ecf20Sopenharmony_ci return -ENODEV; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* Check if we have a MacOS display without a node spec */ 6678c2ecf20Sopenharmony_ci if (of_get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) { 6688c2ecf20Sopenharmony_ci /* The old code tried to work out which node was the MacOS 6698c2ecf20Sopenharmony_ci * display based on the address. I'm dropping that since the 6708c2ecf20Sopenharmony_ci * lack of a node spec only happens with old BootX versions 6718c2ecf20Sopenharmony_ci * (users can update) and with this code, they'll still get 6728c2ecf20Sopenharmony_ci * a display (just not the palette hacks). 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_ci offb_init_nodriver(of_chosen, 1); 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci for_each_node_by_type(dp, "display") { 6788c2ecf20Sopenharmony_ci if (of_get_property(dp, "linux,opened", NULL) && 6798c2ecf20Sopenharmony_ci of_get_property(dp, "linux,boot-display", NULL)) { 6808c2ecf20Sopenharmony_ci boot_disp = dp; 6818c2ecf20Sopenharmony_ci offb_init_nodriver(dp, 0); 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci for_each_node_by_type(dp, "display") { 6858c2ecf20Sopenharmony_ci if (of_get_property(dp, "linux,opened", NULL) && 6868c2ecf20Sopenharmony_ci dp != boot_disp) 6878c2ecf20Sopenharmony_ci offb_init_nodriver(dp, 0); 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci return 0; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cimodule_init(offb_init); 6958c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 696