18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/drivers/video/console/sticore.c - 48c2ecf20Sopenharmony_ci * core code for console driver using HP's STI firmware 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 78c2ecf20Sopenharmony_ci * Copyright (C) 2001-2020 Helge Deller <deller@gmx.de> 88c2ecf20Sopenharmony_ci * Copyright (C) 2001-2002 Thomas Bogendoerfer <tsbogend@alpha.franken.de> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * TODO: 118c2ecf20Sopenharmony_ci * - call STI in virtual mode rather than in real mode 128c2ecf20Sopenharmony_ci * - screen blanking with state_mgmt() in text mode STI ? 138c2ecf20Sopenharmony_ci * - try to make it work on m68k hp workstations ;) 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/types.h> 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/init.h> 248c2ecf20Sopenharmony_ci#include <linux/pci.h> 258c2ecf20Sopenharmony_ci#include <linux/font.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <asm/hardware.h> 288c2ecf20Sopenharmony_ci#include <asm/page.h> 298c2ecf20Sopenharmony_ci#include <asm/parisc-device.h> 308c2ecf20Sopenharmony_ci#include <asm/pdc.h> 318c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 328c2ecf20Sopenharmony_ci#include <asm/grfioctl.h> 338c2ecf20Sopenharmony_ci#include <asm/fb.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "../fbdev/sticore.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define STI_DRIVERVERSION "Version 0.9c" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic struct sti_struct *default_sti __read_mostly; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* number of STI ROMS found and their ptrs to each struct */ 428c2ecf20Sopenharmony_cistatic int num_sti_roms __read_mostly; 438c2ecf20Sopenharmony_cistatic struct sti_struct *sti_roms[MAX_STI_ROMS] __read_mostly; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* The colour indices used by STI are 478c2ecf20Sopenharmony_ci * 0 - Black 488c2ecf20Sopenharmony_ci * 1 - White 498c2ecf20Sopenharmony_ci * 2 - Red 508c2ecf20Sopenharmony_ci * 3 - Yellow/Brown 518c2ecf20Sopenharmony_ci * 4 - Green 528c2ecf20Sopenharmony_ci * 5 - Cyan 538c2ecf20Sopenharmony_ci * 6 - Blue 548c2ecf20Sopenharmony_ci * 7 - Magenta 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * So we have the same colours as VGA (basically one bit each for R, G, B), 578c2ecf20Sopenharmony_ci * but have to translate them, anyway. */ 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic const u8 col_trans[8] = { 608c2ecf20Sopenharmony_ci 0, 6, 4, 5, 618c2ecf20Sopenharmony_ci 2, 7, 3, 1 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define c_fg(sti, c) col_trans[((c>> 8) & 7)] 658c2ecf20Sopenharmony_ci#define c_bg(sti, c) col_trans[((c>>11) & 7)] 668c2ecf20Sopenharmony_ci#define c_index(sti, c) ((c) & 0xff) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic const struct sti_init_flags default_init_flags = { 698c2ecf20Sopenharmony_ci .wait = STI_WAIT, 708c2ecf20Sopenharmony_ci .reset = 1, 718c2ecf20Sopenharmony_ci .text = 1, 728c2ecf20Sopenharmony_ci .nontext = 1, 738c2ecf20Sopenharmony_ci .no_chg_bet = 1, 748c2ecf20Sopenharmony_ci .no_chg_bei = 1, 758c2ecf20Sopenharmony_ci .init_cmap_tx = 1, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int sti_init_graph(struct sti_struct *sti) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct sti_init_inptr *inptr = &sti->sti_data->init_inptr; 818c2ecf20Sopenharmony_ci struct sti_init_inptr_ext *inptr_ext = &sti->sti_data->init_inptr_ext; 828c2ecf20Sopenharmony_ci struct sti_init_outptr *outptr = &sti->sti_data->init_outptr; 838c2ecf20Sopenharmony_ci unsigned long flags; 848c2ecf20Sopenharmony_ci int ret, err; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci spin_lock_irqsave(&sti->lock, flags); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci memset(inptr, 0, sizeof(*inptr)); 898c2ecf20Sopenharmony_ci inptr->text_planes = 3; /* # of text planes (max 3 for STI) */ 908c2ecf20Sopenharmony_ci memset(inptr_ext, 0, sizeof(*inptr_ext)); 918c2ecf20Sopenharmony_ci inptr->ext_ptr = STI_PTR(inptr_ext); 928c2ecf20Sopenharmony_ci outptr->errno = 0; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci ret = sti_call(sti, sti->init_graph, &default_init_flags, inptr, 958c2ecf20Sopenharmony_ci outptr, sti->glob_cfg); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (ret >= 0) 988c2ecf20Sopenharmony_ci sti->text_planes = outptr->text_planes; 998c2ecf20Sopenharmony_ci err = outptr->errno; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sti->lock, flags); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (ret < 0) { 1048c2ecf20Sopenharmony_ci pr_err("STI init_graph failed (ret %d, errno %d)\n", ret, err); 1058c2ecf20Sopenharmony_ci return -1; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const struct sti_conf_flags default_conf_flags = { 1128c2ecf20Sopenharmony_ci .wait = STI_WAIT, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void sti_inq_conf(struct sti_struct *sti) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct sti_conf_inptr *inptr = &sti->sti_data->inq_inptr; 1188c2ecf20Sopenharmony_ci struct sti_conf_outptr *outptr = &sti->sti_data->inq_outptr; 1198c2ecf20Sopenharmony_ci unsigned long flags; 1208c2ecf20Sopenharmony_ci s32 ret; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci outptr->ext_ptr = STI_PTR(&sti->sti_data->inq_outptr_ext); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci do { 1258c2ecf20Sopenharmony_ci spin_lock_irqsave(&sti->lock, flags); 1268c2ecf20Sopenharmony_ci memset(inptr, 0, sizeof(*inptr)); 1278c2ecf20Sopenharmony_ci ret = sti_call(sti, sti->inq_conf, &default_conf_flags, 1288c2ecf20Sopenharmony_ci inptr, outptr, sti->glob_cfg); 1298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sti->lock, flags); 1308c2ecf20Sopenharmony_ci } while (ret == 1); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic const struct sti_font_flags default_font_flags = { 1348c2ecf20Sopenharmony_ci .wait = STI_WAIT, 1358c2ecf20Sopenharmony_ci .non_text = 0, 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_civoid 1398c2ecf20Sopenharmony_cisti_putc(struct sti_struct *sti, int c, int y, int x, 1408c2ecf20Sopenharmony_ci struct sti_cooked_font *font) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct sti_font_inptr *inptr = &sti->sti_data->font_inptr; 1438c2ecf20Sopenharmony_ci struct sti_font_inptr inptr_default = { 1448c2ecf20Sopenharmony_ci .font_start_addr = STI_PTR(font->raw), 1458c2ecf20Sopenharmony_ci .index = c_index(sti, c), 1468c2ecf20Sopenharmony_ci .fg_color = c_fg(sti, c), 1478c2ecf20Sopenharmony_ci .bg_color = c_bg(sti, c), 1488c2ecf20Sopenharmony_ci .dest_x = x * font->width, 1498c2ecf20Sopenharmony_ci .dest_y = y * font->height, 1508c2ecf20Sopenharmony_ci }; 1518c2ecf20Sopenharmony_ci struct sti_font_outptr *outptr = &sti->sti_data->font_outptr; 1528c2ecf20Sopenharmony_ci s32 ret; 1538c2ecf20Sopenharmony_ci unsigned long flags; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci do { 1568c2ecf20Sopenharmony_ci spin_lock_irqsave(&sti->lock, flags); 1578c2ecf20Sopenharmony_ci *inptr = inptr_default; 1588c2ecf20Sopenharmony_ci ret = sti_call(sti, sti->font_unpmv, &default_font_flags, 1598c2ecf20Sopenharmony_ci inptr, outptr, sti->glob_cfg); 1608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sti->lock, flags); 1618c2ecf20Sopenharmony_ci } while (ret == 1); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic const struct sti_blkmv_flags clear_blkmv_flags = { 1658c2ecf20Sopenharmony_ci .wait = STI_WAIT, 1668c2ecf20Sopenharmony_ci .color = 1, 1678c2ecf20Sopenharmony_ci .clear = 1, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_civoid 1718c2ecf20Sopenharmony_cisti_set(struct sti_struct *sti, int src_y, int src_x, 1728c2ecf20Sopenharmony_ci int height, int width, u8 color) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr; 1758c2ecf20Sopenharmony_ci struct sti_blkmv_inptr inptr_default = { 1768c2ecf20Sopenharmony_ci .fg_color = color, 1778c2ecf20Sopenharmony_ci .bg_color = color, 1788c2ecf20Sopenharmony_ci .src_x = src_x, 1798c2ecf20Sopenharmony_ci .src_y = src_y, 1808c2ecf20Sopenharmony_ci .dest_x = src_x, 1818c2ecf20Sopenharmony_ci .dest_y = src_y, 1828c2ecf20Sopenharmony_ci .width = width, 1838c2ecf20Sopenharmony_ci .height = height, 1848c2ecf20Sopenharmony_ci }; 1858c2ecf20Sopenharmony_ci struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr; 1868c2ecf20Sopenharmony_ci s32 ret; 1878c2ecf20Sopenharmony_ci unsigned long flags; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci do { 1908c2ecf20Sopenharmony_ci spin_lock_irqsave(&sti->lock, flags); 1918c2ecf20Sopenharmony_ci *inptr = inptr_default; 1928c2ecf20Sopenharmony_ci ret = sti_call(sti, sti->block_move, &clear_blkmv_flags, 1938c2ecf20Sopenharmony_ci inptr, outptr, sti->glob_cfg); 1948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sti->lock, flags); 1958c2ecf20Sopenharmony_ci } while (ret == 1); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_civoid 1998c2ecf20Sopenharmony_cisti_clear(struct sti_struct *sti, int src_y, int src_x, 2008c2ecf20Sopenharmony_ci int height, int width, int c, struct sti_cooked_font *font) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr; 2038c2ecf20Sopenharmony_ci struct sti_blkmv_inptr inptr_default = { 2048c2ecf20Sopenharmony_ci .fg_color = c_fg(sti, c), 2058c2ecf20Sopenharmony_ci .bg_color = c_bg(sti, c), 2068c2ecf20Sopenharmony_ci .src_x = src_x * font->width, 2078c2ecf20Sopenharmony_ci .src_y = src_y * font->height, 2088c2ecf20Sopenharmony_ci .dest_x = src_x * font->width, 2098c2ecf20Sopenharmony_ci .dest_y = src_y * font->height, 2108c2ecf20Sopenharmony_ci .width = width * font->width, 2118c2ecf20Sopenharmony_ci .height = height * font->height, 2128c2ecf20Sopenharmony_ci }; 2138c2ecf20Sopenharmony_ci struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr; 2148c2ecf20Sopenharmony_ci s32 ret; 2158c2ecf20Sopenharmony_ci unsigned long flags; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci do { 2188c2ecf20Sopenharmony_ci spin_lock_irqsave(&sti->lock, flags); 2198c2ecf20Sopenharmony_ci *inptr = inptr_default; 2208c2ecf20Sopenharmony_ci ret = sti_call(sti, sti->block_move, &clear_blkmv_flags, 2218c2ecf20Sopenharmony_ci inptr, outptr, sti->glob_cfg); 2228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sti->lock, flags); 2238c2ecf20Sopenharmony_ci } while (ret == 1); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic const struct sti_blkmv_flags default_blkmv_flags = { 2278c2ecf20Sopenharmony_ci .wait = STI_WAIT, 2288c2ecf20Sopenharmony_ci}; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_civoid 2318c2ecf20Sopenharmony_cisti_bmove(struct sti_struct *sti, int src_y, int src_x, 2328c2ecf20Sopenharmony_ci int dst_y, int dst_x, int height, int width, 2338c2ecf20Sopenharmony_ci struct sti_cooked_font *font) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr; 2368c2ecf20Sopenharmony_ci struct sti_blkmv_inptr inptr_default = { 2378c2ecf20Sopenharmony_ci .src_x = src_x * font->width, 2388c2ecf20Sopenharmony_ci .src_y = src_y * font->height, 2398c2ecf20Sopenharmony_ci .dest_x = dst_x * font->width, 2408c2ecf20Sopenharmony_ci .dest_y = dst_y * font->height, 2418c2ecf20Sopenharmony_ci .width = width * font->width, 2428c2ecf20Sopenharmony_ci .height = height * font->height, 2438c2ecf20Sopenharmony_ci }; 2448c2ecf20Sopenharmony_ci struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr; 2458c2ecf20Sopenharmony_ci s32 ret; 2468c2ecf20Sopenharmony_ci unsigned long flags; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci do { 2498c2ecf20Sopenharmony_ci spin_lock_irqsave(&sti->lock, flags); 2508c2ecf20Sopenharmony_ci *inptr = inptr_default; 2518c2ecf20Sopenharmony_ci ret = sti_call(sti, sti->block_move, &default_blkmv_flags, 2528c2ecf20Sopenharmony_ci inptr, outptr, sti->glob_cfg); 2538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sti->lock, flags); 2548c2ecf20Sopenharmony_ci } while (ret == 1); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void sti_flush(unsigned long start, unsigned long end) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci flush_icache_range(start, end); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic void sti_rom_copy(unsigned long base, unsigned long count, void *dest) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci unsigned long dest_start = (unsigned long) dest; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */ 2688c2ecf20Sopenharmony_ci while (count >= 4) { 2698c2ecf20Sopenharmony_ci count -= 4; 2708c2ecf20Sopenharmony_ci *(u32 *)dest = gsc_readl(base); 2718c2ecf20Sopenharmony_ci base += 4; 2728c2ecf20Sopenharmony_ci dest += 4; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci while (count) { 2758c2ecf20Sopenharmony_ci count--; 2768c2ecf20Sopenharmony_ci *(u8 *)dest = gsc_readb(base); 2778c2ecf20Sopenharmony_ci base++; 2788c2ecf20Sopenharmony_ci dest++; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci sti_flush(dest_start, (unsigned long)dest); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic char default_sti_path[21] __read_mostly; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#ifndef MODULE 2908c2ecf20Sopenharmony_cistatic int __init sti_setup(char *str) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci if (str) 2938c2ecf20Sopenharmony_ci strlcpy (default_sti_path, str, sizeof (default_sti_path)); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return 1; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* Assuming the machine has multiple STI consoles (=graphic cards) which 2998c2ecf20Sopenharmony_ci * all get detected by sticon, the user may define with the linux kernel 3008c2ecf20Sopenharmony_ci * parameter sti=<x> which of them will be the initial boot-console. 3018c2ecf20Sopenharmony_ci * <x> is a number between 0 and MAX_STI_ROMS, with 0 as the default 3028c2ecf20Sopenharmony_ci * STI screen. 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci__setup("sti=", sti_setup); 3058c2ecf20Sopenharmony_ci#endif 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic char *font_name; 3108c2ecf20Sopenharmony_cistatic int font_index, 3118c2ecf20Sopenharmony_ci font_height, 3128c2ecf20Sopenharmony_ci font_width; 3138c2ecf20Sopenharmony_ci#ifndef MODULE 3148c2ecf20Sopenharmony_cistatic int sti_font_setup(char *str) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci /* 3178c2ecf20Sopenharmony_ci * The default font can be selected in various ways. 3188c2ecf20Sopenharmony_ci * a) sti_font=VGA8x16, sti_font=10x20, sti_font=10*20 selects 3198c2ecf20Sopenharmony_ci * an built-in Linux framebuffer font. 3208c2ecf20Sopenharmony_ci * b) sti_font=<index>, where index is (1..x) with 1 selecting 3218c2ecf20Sopenharmony_ci * the first HP STI ROM built-in font.. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (*str >= '0' && *str <= '9') { 3258c2ecf20Sopenharmony_ci char *x; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) { 3288c2ecf20Sopenharmony_ci font_height = simple_strtoul(str, NULL, 0); 3298c2ecf20Sopenharmony_ci font_width = simple_strtoul(x+1, NULL, 0); 3308c2ecf20Sopenharmony_ci } else { 3318c2ecf20Sopenharmony_ci font_index = simple_strtoul(str, NULL, 0); 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci } else { 3348c2ecf20Sopenharmony_ci font_name = str; /* fb font name */ 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return 1; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* The optional linux kernel parameter "sti_font" defines which font 3418c2ecf20Sopenharmony_ci * should be used by the sticon driver to draw characters to the screen. 3428c2ecf20Sopenharmony_ci * Possible values are: 3438c2ecf20Sopenharmony_ci * - sti_font=<fb_fontname>: 3448c2ecf20Sopenharmony_ci * <fb_fontname> is the name of one of the linux-kernel built-in 3458c2ecf20Sopenharmony_ci * framebuffer font names (e.g. VGA8x16, SUN22x18). 3468c2ecf20Sopenharmony_ci * This is only available if the fonts have been statically compiled 3478c2ecf20Sopenharmony_ci * in with e.g. the CONFIG_FONT_8x16 or CONFIG_FONT_SUN12x22 options. 3488c2ecf20Sopenharmony_ci * - sti_font=<number> (<number> = 1,2,3,...) 3498c2ecf20Sopenharmony_ci * most STI ROMs have built-in HP specific fonts, which can be selected 3508c2ecf20Sopenharmony_ci * by giving the desired number to the sticon driver. 3518c2ecf20Sopenharmony_ci * NOTE: This number is machine and STI ROM dependend. 3528c2ecf20Sopenharmony_ci * - sti_font=<height>x<width> (e.g. sti_font=16x8) 3538c2ecf20Sopenharmony_ci * <height> and <width> gives hints to the height and width of the 3548c2ecf20Sopenharmony_ci * font which the user wants. The sticon driver will try to use 3558c2ecf20Sopenharmony_ci * a font with this height and width, but if no suitable font is 3568c2ecf20Sopenharmony_ci * found, sticon will use the default 8x8 font. 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_ci__setup("sti_font=", sti_font_setup); 3598c2ecf20Sopenharmony_ci#endif 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic void sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, 3648c2ecf20Sopenharmony_ci unsigned int sti_mem_request) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct sti_glob_cfg_ext *cfg; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci pr_debug("%d text planes\n" 3698c2ecf20Sopenharmony_ci "%4d x %4d screen resolution\n" 3708c2ecf20Sopenharmony_ci "%4d x %4d offscreen\n" 3718c2ecf20Sopenharmony_ci "%4d x %4d layout\n" 3728c2ecf20Sopenharmony_ci "regions at %08x %08x %08x %08x\n" 3738c2ecf20Sopenharmony_ci "regions at %08x %08x %08x %08x\n" 3748c2ecf20Sopenharmony_ci "reent_lvl %d\n" 3758c2ecf20Sopenharmony_ci "save_addr %08x\n", 3768c2ecf20Sopenharmony_ci glob_cfg->text_planes, 3778c2ecf20Sopenharmony_ci glob_cfg->onscreen_x, glob_cfg->onscreen_y, 3788c2ecf20Sopenharmony_ci glob_cfg->offscreen_x, glob_cfg->offscreen_y, 3798c2ecf20Sopenharmony_ci glob_cfg->total_x, glob_cfg->total_y, 3808c2ecf20Sopenharmony_ci glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1], 3818c2ecf20Sopenharmony_ci glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3], 3828c2ecf20Sopenharmony_ci glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5], 3838c2ecf20Sopenharmony_ci glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7], 3848c2ecf20Sopenharmony_ci glob_cfg->reent_lvl, 3858c2ecf20Sopenharmony_ci glob_cfg->save_addr); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* dump extended cfg */ 3888c2ecf20Sopenharmony_ci cfg = PTR_STI((unsigned long)glob_cfg->ext_ptr); 3898c2ecf20Sopenharmony_ci pr_debug("monitor %d\n" 3908c2ecf20Sopenharmony_ci "in friendly mode: %d\n" 3918c2ecf20Sopenharmony_ci "power consumption %d watts\n" 3928c2ecf20Sopenharmony_ci "freq ref %d\n" 3938c2ecf20Sopenharmony_ci "sti_mem_addr %08x (size=%d bytes)\n", 3948c2ecf20Sopenharmony_ci cfg->curr_mon, 3958c2ecf20Sopenharmony_ci cfg->friendly_boot, 3968c2ecf20Sopenharmony_ci cfg->power, 3978c2ecf20Sopenharmony_ci cfg->freq_ref, 3988c2ecf20Sopenharmony_ci cfg->sti_mem_addr, sti_mem_request); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic void sti_dump_outptr(struct sti_struct *sti) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci pr_debug("%d bits per pixel\n" 4048c2ecf20Sopenharmony_ci "%d used bits\n" 4058c2ecf20Sopenharmony_ci "%d planes\n" 4068c2ecf20Sopenharmony_ci "attributes %08x\n", 4078c2ecf20Sopenharmony_ci sti->sti_data->inq_outptr.bits_per_pixel, 4088c2ecf20Sopenharmony_ci sti->sti_data->inq_outptr.bits_used, 4098c2ecf20Sopenharmony_ci sti->sti_data->inq_outptr.planes, 4108c2ecf20Sopenharmony_ci sti->sti_data->inq_outptr.attributes); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address, 4148c2ecf20Sopenharmony_ci unsigned long hpa) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct sti_glob_cfg *glob_cfg; 4178c2ecf20Sopenharmony_ci struct sti_glob_cfg_ext *glob_cfg_ext; 4188c2ecf20Sopenharmony_ci void *save_addr; 4198c2ecf20Sopenharmony_ci void *sti_mem_addr; 4208c2ecf20Sopenharmony_ci int i, size; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (sti->sti_mem_request < 256) 4238c2ecf20Sopenharmony_ci sti->sti_mem_request = 256; /* STI default */ 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci size = sizeof(struct sti_all_data) + sti->sti_mem_request - 256; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci sti->sti_data = kzalloc(size, STI_LOWMEM); 4288c2ecf20Sopenharmony_ci if (!sti->sti_data) 4298c2ecf20Sopenharmony_ci return -ENOMEM; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci glob_cfg = &sti->sti_data->glob_cfg; 4328c2ecf20Sopenharmony_ci glob_cfg_ext = &sti->sti_data->glob_cfg_ext; 4338c2ecf20Sopenharmony_ci save_addr = &sti->sti_data->save_addr; 4348c2ecf20Sopenharmony_ci sti_mem_addr = &sti->sti_data->sti_mem_addr; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext); 4378c2ecf20Sopenharmony_ci glob_cfg->save_addr = STI_PTR(save_addr); 4388c2ecf20Sopenharmony_ci for (i=0; i<8; i++) { 4398c2ecf20Sopenharmony_ci unsigned long newhpa, len; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (sti->pd) { 4428c2ecf20Sopenharmony_ci unsigned char offs = sti->rm_entry[i]; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (offs == 0) 4458c2ecf20Sopenharmony_ci continue; 4468c2ecf20Sopenharmony_ci if (offs != PCI_ROM_ADDRESS && 4478c2ecf20Sopenharmony_ci (offs < PCI_BASE_ADDRESS_0 || 4488c2ecf20Sopenharmony_ci offs > PCI_BASE_ADDRESS_5)) { 4498c2ecf20Sopenharmony_ci pr_warn("STI pci region mapping for region %d (%02x) can't be mapped\n", 4508c2ecf20Sopenharmony_ci i,sti->rm_entry[i]); 4518c2ecf20Sopenharmony_ci continue; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci newhpa = pci_resource_start (sti->pd, (offs - PCI_BASE_ADDRESS_0) / 4); 4548c2ecf20Sopenharmony_ci } else 4558c2ecf20Sopenharmony_ci newhpa = (i == 0) ? rom_address : hpa; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci sti->regions_phys[i] = 4588c2ecf20Sopenharmony_ci REGION_OFFSET_TO_PHYS(sti->regions[i], newhpa); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci len = sti->regions[i].region_desc.length * 4096; 4618c2ecf20Sopenharmony_ci if (len) 4628c2ecf20Sopenharmony_ci glob_cfg->region_ptrs[i] = sti->regions_phys[i]; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci pr_debug("region #%d: phys %08lx, region_ptr %08x, len=%lukB, " 4658c2ecf20Sopenharmony_ci "btlb=%d, sysonly=%d, cache=%d, last=%d\n", 4668c2ecf20Sopenharmony_ci i, sti->regions_phys[i], glob_cfg->region_ptrs[i], 4678c2ecf20Sopenharmony_ci len/1024, 4688c2ecf20Sopenharmony_ci sti->regions[i].region_desc.btlb, 4698c2ecf20Sopenharmony_ci sti->regions[i].region_desc.sys_only, 4708c2ecf20Sopenharmony_ci sti->regions[i].region_desc.cache, 4718c2ecf20Sopenharmony_ci sti->regions[i].region_desc.last); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* last entry reached ? */ 4748c2ecf20Sopenharmony_ci if (sti->regions[i].region_desc.last) 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (++i<8 && sti->regions[i].region) 4798c2ecf20Sopenharmony_ci pr_warn("future ptr (0x%8x) not yet supported !\n", 4808c2ecf20Sopenharmony_ci sti->regions[i].region); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci sti->glob_cfg = glob_cfg; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci#ifdef CONFIG_FONT_SUPPORT 4908c2ecf20Sopenharmony_cistatic struct sti_cooked_font * 4918c2ecf20Sopenharmony_cisti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci const struct font_desc *fbfont = NULL; 4948c2ecf20Sopenharmony_ci unsigned int size, bpc; 4958c2ecf20Sopenharmony_ci void *dest; 4968c2ecf20Sopenharmony_ci struct sti_rom_font *nf; 4978c2ecf20Sopenharmony_ci struct sti_cooked_font *cooked_font; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (fbfont_name && strlen(fbfont_name)) 5008c2ecf20Sopenharmony_ci fbfont = find_font(fbfont_name); 5018c2ecf20Sopenharmony_ci if (!fbfont) 5028c2ecf20Sopenharmony_ci fbfont = get_default_font(1024,768, ~(u32)0, ~(u32)0); 5038c2ecf20Sopenharmony_ci if (!fbfont) 5048c2ecf20Sopenharmony_ci return NULL; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci pr_info(" using %ux%u framebuffer font %s\n", 5078c2ecf20Sopenharmony_ci fbfont->width, fbfont->height, fbfont->name); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci bpc = ((fbfont->width+7)/8) * fbfont->height; 5108c2ecf20Sopenharmony_ci size = bpc * 256; 5118c2ecf20Sopenharmony_ci size += sizeof(struct sti_rom_font); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci nf = kzalloc(size, STI_LOWMEM); 5148c2ecf20Sopenharmony_ci if (!nf) 5158c2ecf20Sopenharmony_ci return NULL; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci nf->first_char = 0; 5188c2ecf20Sopenharmony_ci nf->last_char = 255; 5198c2ecf20Sopenharmony_ci nf->width = fbfont->width; 5208c2ecf20Sopenharmony_ci nf->height = fbfont->height; 5218c2ecf20Sopenharmony_ci nf->font_type = STI_FONT_HPROMAN8; 5228c2ecf20Sopenharmony_ci nf->bytes_per_char = bpc; 5238c2ecf20Sopenharmony_ci nf->next_font = 0; 5248c2ecf20Sopenharmony_ci nf->underline_height = 1; 5258c2ecf20Sopenharmony_ci nf->underline_pos = fbfont->height - nf->underline_height; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci dest = nf; 5288c2ecf20Sopenharmony_ci dest += sizeof(struct sti_rom_font); 5298c2ecf20Sopenharmony_ci memcpy(dest, fbfont->data, bpc*256); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci cooked_font = kzalloc(sizeof(*cooked_font), GFP_KERNEL); 5328c2ecf20Sopenharmony_ci if (!cooked_font) { 5338c2ecf20Sopenharmony_ci kfree(nf); 5348c2ecf20Sopenharmony_ci return NULL; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci cooked_font->raw = nf; 5388c2ecf20Sopenharmony_ci cooked_font->raw_ptr = nf; 5398c2ecf20Sopenharmony_ci cooked_font->next_font = NULL; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci cooked_rom->font_start = cooked_font; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return cooked_font; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci#else 5468c2ecf20Sopenharmony_cistatic struct sti_cooked_font * 5478c2ecf20Sopenharmony_cisti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci return NULL; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci#endif 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic int sti_search_font(struct sti_cooked_rom *rom, int height, int width) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct sti_cooked_font *font; 5568c2ecf20Sopenharmony_ci int i = 0; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci for (font = rom->font_start; font; font = font->next_font, i++) { 5598c2ecf20Sopenharmony_ci if ((font->raw->width == width) && 5608c2ecf20Sopenharmony_ci (font->raw->height == height)) 5618c2ecf20Sopenharmony_ci return i; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic struct sti_cooked_font *sti_select_font(struct sti_cooked_rom *rom) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct sti_cooked_font *font; 5698c2ecf20Sopenharmony_ci int i; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* check for framebuffer-font first */ 5728c2ecf20Sopenharmony_ci if (!font_index) { 5738c2ecf20Sopenharmony_ci font = sti_select_fbfont(rom, font_name); 5748c2ecf20Sopenharmony_ci if (font) 5758c2ecf20Sopenharmony_ci return font; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (font_width && font_height) 5798c2ecf20Sopenharmony_ci font_index = sti_search_font(rom, 5808c2ecf20Sopenharmony_ci font_height, font_width); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci for (font = rom->font_start, i = font_index - 1; 5838c2ecf20Sopenharmony_ci font && (i > 0); 5848c2ecf20Sopenharmony_ci font = font->next_font, i--); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (font) 5878c2ecf20Sopenharmony_ci return font; 5888c2ecf20Sopenharmony_ci else 5898c2ecf20Sopenharmony_ci return rom->font_start; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic void sti_dump_rom(struct sti_struct *sti) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci struct sti_rom *rom = sti->rom->raw; 5968c2ecf20Sopenharmony_ci struct sti_cooked_font *font_start; 5978c2ecf20Sopenharmony_ci int nr; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci pr_info(" id %04x-%04x, conforms to spec rev. %d.%02x\n", 6008c2ecf20Sopenharmony_ci rom->graphics_id[0], 6018c2ecf20Sopenharmony_ci rom->graphics_id[1], 6028c2ecf20Sopenharmony_ci rom->revno[0] >> 4, 6038c2ecf20Sopenharmony_ci rom->revno[0] & 0x0f); 6048c2ecf20Sopenharmony_ci pr_debug(" supports %d monitors\n", rom->num_mons); 6058c2ecf20Sopenharmony_ci pr_debug(" font start %08x\n", rom->font_start); 6068c2ecf20Sopenharmony_ci pr_debug(" region list %08x\n", rom->region_list); 6078c2ecf20Sopenharmony_ci pr_debug(" init_graph %08x\n", rom->init_graph); 6088c2ecf20Sopenharmony_ci pr_debug(" bus support %02x\n", rom->bus_support); 6098c2ecf20Sopenharmony_ci pr_debug(" ext bus support %02x\n", rom->ext_bus_support); 6108c2ecf20Sopenharmony_ci pr_debug(" alternate code type %d\n", rom->alt_code_type); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci font_start = sti->rom->font_start; 6138c2ecf20Sopenharmony_ci nr = 0; 6148c2ecf20Sopenharmony_ci while (font_start) { 6158c2ecf20Sopenharmony_ci struct sti_rom_font *f = font_start->raw; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci pr_info(" built-in font #%d: size %dx%d, chars %d-%d, bpc %d\n", ++nr, 6188c2ecf20Sopenharmony_ci f->width, f->height, 6198c2ecf20Sopenharmony_ci f->first_char, f->last_char, f->bytes_per_char); 6208c2ecf20Sopenharmony_ci font_start = font_start->next_font; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int sti_cook_fonts(struct sti_cooked_rom *cooked_rom, 6268c2ecf20Sopenharmony_ci struct sti_rom *raw_rom) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct sti_rom_font *raw_font, *font_start; 6298c2ecf20Sopenharmony_ci struct sti_cooked_font *cooked_font; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci cooked_font = kzalloc(sizeof(*cooked_font), GFP_KERNEL); 6328c2ecf20Sopenharmony_ci if (!cooked_font) 6338c2ecf20Sopenharmony_ci return 0; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci cooked_rom->font_start = cooked_font; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci raw_font = ((void *)raw_rom) + (raw_rom->font_start); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci font_start = raw_font; 6408c2ecf20Sopenharmony_ci cooked_font->raw = raw_font; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci while (raw_font->next_font) { 6438c2ecf20Sopenharmony_ci raw_font = ((void *)font_start) + (raw_font->next_font); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci cooked_font->next_font = kzalloc(sizeof(*cooked_font), GFP_KERNEL); 6468c2ecf20Sopenharmony_ci if (!cooked_font->next_font) 6478c2ecf20Sopenharmony_ci return 1; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci cooked_font = cooked_font->next_font; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci cooked_font->raw = raw_font; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci cooked_font->next_font = NULL; 6558c2ecf20Sopenharmony_ci return 1; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci#define BMODE_RELOCATE(offset) offset = (offset) / 4; 6598c2ecf20Sopenharmony_ci#define BMODE_LAST_ADDR_OFFS 0x50 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_civoid sti_font_convert_bytemode(struct sti_struct *sti, struct sti_cooked_font *f) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci unsigned char *n, *p, *q; 6648c2ecf20Sopenharmony_ci int size = f->raw->bytes_per_char * 256 + sizeof(struct sti_rom_font); 6658c2ecf20Sopenharmony_ci struct sti_rom_font *old_font; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (sti->wordmode) 6688c2ecf20Sopenharmony_ci return; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci old_font = f->raw_ptr; 6718c2ecf20Sopenharmony_ci n = kcalloc(4, size, STI_LOWMEM); 6728c2ecf20Sopenharmony_ci f->raw_ptr = n; 6738c2ecf20Sopenharmony_ci if (!n) 6748c2ecf20Sopenharmony_ci return; 6758c2ecf20Sopenharmony_ci p = n + 3; 6768c2ecf20Sopenharmony_ci q = (unsigned char *) f->raw; 6778c2ecf20Sopenharmony_ci while (size--) { 6788c2ecf20Sopenharmony_ci *p = *q++; 6798c2ecf20Sopenharmony_ci p += 4; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci /* store new ptr to byte-mode font and delete old font */ 6828c2ecf20Sopenharmony_ci f->raw = (struct sti_rom_font *) (n + 3); 6838c2ecf20Sopenharmony_ci kfree(old_font); 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sti_font_convert_bytemode); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic void sti_bmode_rom_copy(unsigned long base, unsigned long count, 6888c2ecf20Sopenharmony_ci void *dest) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci unsigned long dest_start = (unsigned long) dest; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci while (count) { 6938c2ecf20Sopenharmony_ci count--; 6948c2ecf20Sopenharmony_ci *(u8 *)dest = gsc_readl(base); 6958c2ecf20Sopenharmony_ci base += 4; 6968c2ecf20Sopenharmony_ci dest++; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci sti_flush(dest_start, (unsigned long)dest); 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic struct sti_rom *sti_get_bmode_rom (unsigned long address) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct sti_rom *raw; 7058c2ecf20Sopenharmony_ci u32 size; 7068c2ecf20Sopenharmony_ci struct sti_rom_font *raw_font, *font_start; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci sti_bmode_rom_copy(address + BMODE_LAST_ADDR_OFFS, sizeof(size), &size); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci size = (size+3) / 4; 7118c2ecf20Sopenharmony_ci raw = kmalloc(size, STI_LOWMEM); 7128c2ecf20Sopenharmony_ci if (raw) { 7138c2ecf20Sopenharmony_ci sti_bmode_rom_copy(address, size, raw); 7148c2ecf20Sopenharmony_ci memmove (&raw->res004, &raw->type[0], 0x3c); 7158c2ecf20Sopenharmony_ci raw->type[3] = raw->res004; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci BMODE_RELOCATE (raw->region_list); 7188c2ecf20Sopenharmony_ci BMODE_RELOCATE (raw->font_start); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci BMODE_RELOCATE (raw->init_graph); 7218c2ecf20Sopenharmony_ci BMODE_RELOCATE (raw->state_mgmt); 7228c2ecf20Sopenharmony_ci BMODE_RELOCATE (raw->font_unpmv); 7238c2ecf20Sopenharmony_ci BMODE_RELOCATE (raw->block_move); 7248c2ecf20Sopenharmony_ci BMODE_RELOCATE (raw->inq_conf); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci raw_font = ((void *)raw) + raw->font_start; 7278c2ecf20Sopenharmony_ci font_start = raw_font; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci while (raw_font->next_font) { 7308c2ecf20Sopenharmony_ci BMODE_RELOCATE (raw_font->next_font); 7318c2ecf20Sopenharmony_ci raw_font = ((void *)font_start) + raw_font->next_font; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci return raw; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic struct sti_rom *sti_get_wmode_rom(unsigned long address) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct sti_rom *raw; 7408c2ecf20Sopenharmony_ci unsigned long size; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* read the ROM size directly from the struct in ROM */ 7438c2ecf20Sopenharmony_ci size = gsc_readl(address + offsetof(struct sti_rom,last_addr)); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci raw = kmalloc(size, STI_LOWMEM); 7468c2ecf20Sopenharmony_ci if (raw) 7478c2ecf20Sopenharmony_ci sti_rom_copy(address, size, raw); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return raw; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic int sti_read_rom(int wordmode, struct sti_struct *sti, 7538c2ecf20Sopenharmony_ci unsigned long address) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct sti_cooked_rom *cooked; 7568c2ecf20Sopenharmony_ci struct sti_rom *raw = NULL; 7578c2ecf20Sopenharmony_ci unsigned long revno; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci cooked = kmalloc(sizeof *cooked, GFP_KERNEL); 7608c2ecf20Sopenharmony_ci if (!cooked) 7618c2ecf20Sopenharmony_ci goto out_err; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (wordmode) 7648c2ecf20Sopenharmony_ci raw = sti_get_wmode_rom (address); 7658c2ecf20Sopenharmony_ci else 7668c2ecf20Sopenharmony_ci raw = sti_get_bmode_rom (address); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (!raw) 7698c2ecf20Sopenharmony_ci goto out_err; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (!sti_cook_fonts(cooked, raw)) { 7728c2ecf20Sopenharmony_ci pr_warn("No font found for STI at %08lx\n", address); 7738c2ecf20Sopenharmony_ci goto out_err; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (raw->region_list) 7778c2ecf20Sopenharmony_ci memcpy(sti->regions, ((void *)raw)+raw->region_list, sizeof(sti->regions)); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci address = (unsigned long) STI_PTR(raw); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci pr_info("STI %s ROM supports 32 %sbit firmware functions.\n", 7828c2ecf20Sopenharmony_ci wordmode ? "word mode" : "byte mode", 7838c2ecf20Sopenharmony_ci raw->alt_code_type == ALT_CODE_TYPE_PA_RISC_64 7848c2ecf20Sopenharmony_ci ? "and 64 " : ""); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci sti->font_unpmv = address + (raw->font_unpmv & 0x03ffffff); 7878c2ecf20Sopenharmony_ci sti->block_move = address + (raw->block_move & 0x03ffffff); 7888c2ecf20Sopenharmony_ci sti->init_graph = address + (raw->init_graph & 0x03ffffff); 7898c2ecf20Sopenharmony_ci sti->inq_conf = address + (raw->inq_conf & 0x03ffffff); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci sti->rom = cooked; 7928c2ecf20Sopenharmony_ci sti->rom->raw = raw; 7938c2ecf20Sopenharmony_ci sti_dump_rom(sti); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci sti->wordmode = wordmode; 7968c2ecf20Sopenharmony_ci sti->font = sti_select_font(sti->rom); 7978c2ecf20Sopenharmony_ci sti->font->width = sti->font->raw->width; 7988c2ecf20Sopenharmony_ci sti->font->height = sti->font->raw->height; 7998c2ecf20Sopenharmony_ci sti_font_convert_bytemode(sti, sti->font); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci sti->sti_mem_request = raw->sti_mem_req; 8028c2ecf20Sopenharmony_ci sti->graphics_id[0] = raw->graphics_id[0]; 8038c2ecf20Sopenharmony_ci sti->graphics_id[1] = raw->graphics_id[1]; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* check if the ROM routines in this card are compatible */ 8068c2ecf20Sopenharmony_ci if (wordmode || sti->graphics_id[1] != 0x09A02587) 8078c2ecf20Sopenharmony_ci goto ok; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci revno = (raw->revno[0] << 8) | raw->revno[1]; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci switch (sti->graphics_id[0]) { 8128c2ecf20Sopenharmony_ci case S9000_ID_HCRX: 8138c2ecf20Sopenharmony_ci /* HyperA or HyperB ? */ 8148c2ecf20Sopenharmony_ci if (revno == 0x8408 || revno == 0x840b) 8158c2ecf20Sopenharmony_ci goto msg_not_supported; 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci case CRT_ID_THUNDER: 8188c2ecf20Sopenharmony_ci if (revno == 0x8509) 8198c2ecf20Sopenharmony_ci goto msg_not_supported; 8208c2ecf20Sopenharmony_ci break; 8218c2ecf20Sopenharmony_ci case CRT_ID_THUNDER2: 8228c2ecf20Sopenharmony_ci if (revno == 0x850c) 8238c2ecf20Sopenharmony_ci goto msg_not_supported; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ciok: 8268c2ecf20Sopenharmony_ci return 1; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cimsg_not_supported: 8298c2ecf20Sopenharmony_ci pr_warn("Sorry, this GSC/STI card is not yet supported.\n"); 8308c2ecf20Sopenharmony_ci pr_warn("Please see https://parisc.wiki.kernel.org/" 8318c2ecf20Sopenharmony_ci "index.php/Graphics_howto for more info.\n"); 8328c2ecf20Sopenharmony_ci /* fall through */ 8338c2ecf20Sopenharmony_ciout_err: 8348c2ecf20Sopenharmony_ci kfree(raw); 8358c2ecf20Sopenharmony_ci kfree(cooked); 8368c2ecf20Sopenharmony_ci return 0; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic struct sti_struct *sti_try_rom_generic(unsigned long address, 8408c2ecf20Sopenharmony_ci unsigned long hpa, 8418c2ecf20Sopenharmony_ci struct pci_dev *pd) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct sti_struct *sti; 8448c2ecf20Sopenharmony_ci int ok; 8458c2ecf20Sopenharmony_ci u32 sig; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (num_sti_roms >= MAX_STI_ROMS) { 8488c2ecf20Sopenharmony_ci pr_warn("maximum number of STI ROMS reached !\n"); 8498c2ecf20Sopenharmony_ci return NULL; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci sti = kzalloc(sizeof(*sti), GFP_KERNEL); 8538c2ecf20Sopenharmony_ci if (!sti) 8548c2ecf20Sopenharmony_ci return NULL; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci spin_lock_init(&sti->lock); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_citest_rom: 8598c2ecf20Sopenharmony_ci /* if we can't read the ROM, bail out early. Not being able 8608c2ecf20Sopenharmony_ci * to read the hpa is okay, for romless sti */ 8618c2ecf20Sopenharmony_ci if (pdc_add_valid(address)) 8628c2ecf20Sopenharmony_ci goto out_err; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci sig = gsc_readl(address); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* check for a PCI ROM structure */ 8678c2ecf20Sopenharmony_ci if ((le32_to_cpu(sig)==0xaa55)) { 8688c2ecf20Sopenharmony_ci unsigned int i, rm_offset; 8698c2ecf20Sopenharmony_ci u32 *rm; 8708c2ecf20Sopenharmony_ci i = gsc_readl(address+0x04); 8718c2ecf20Sopenharmony_ci if (i != 1) { 8728c2ecf20Sopenharmony_ci /* The ROM could have multiple architecture 8738c2ecf20Sopenharmony_ci * dependent images (e.g. i386, parisc,...) */ 8748c2ecf20Sopenharmony_ci pr_warn("PCI ROM is not a STI ROM type image (0x%8x)\n", i); 8758c2ecf20Sopenharmony_ci goto out_err; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci sti->pd = pd; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci i = gsc_readl(address+0x0c); 8818c2ecf20Sopenharmony_ci pr_debug("PCI ROM size (from header) = %d kB\n", 8828c2ecf20Sopenharmony_ci le16_to_cpu(i>>16)*512/1024); 8838c2ecf20Sopenharmony_ci rm_offset = le16_to_cpu(i & 0xffff); 8848c2ecf20Sopenharmony_ci if (rm_offset) { 8858c2ecf20Sopenharmony_ci /* read 16 bytes from the pci region mapper array */ 8868c2ecf20Sopenharmony_ci rm = (u32*) &sti->rm_entry; 8878c2ecf20Sopenharmony_ci *rm++ = gsc_readl(address+rm_offset+0x00); 8888c2ecf20Sopenharmony_ci *rm++ = gsc_readl(address+rm_offset+0x04); 8898c2ecf20Sopenharmony_ci *rm++ = gsc_readl(address+rm_offset+0x08); 8908c2ecf20Sopenharmony_ci *rm++ = gsc_readl(address+rm_offset+0x0c); 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci address += le32_to_cpu(gsc_readl(address+8)); 8948c2ecf20Sopenharmony_ci pr_debug("sig %04x, PCI STI ROM at %08lx\n", sig, address); 8958c2ecf20Sopenharmony_ci goto test_rom; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci ok = 0; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if ((sig & 0xff) == 0x01) { 9018c2ecf20Sopenharmony_ci pr_debug(" byte mode ROM at %08lx, hpa at %08lx\n", 9028c2ecf20Sopenharmony_ci address, hpa); 9038c2ecf20Sopenharmony_ci ok = sti_read_rom(0, sti, address); 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if ((sig & 0xffff) == 0x0303) { 9078c2ecf20Sopenharmony_ci pr_debug(" word mode ROM at %08lx, hpa at %08lx\n", 9088c2ecf20Sopenharmony_ci address, hpa); 9098c2ecf20Sopenharmony_ci ok = sti_read_rom(1, sti, address); 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (!ok) 9138c2ecf20Sopenharmony_ci goto out_err; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (sti_init_glob_cfg(sti, address, hpa)) 9168c2ecf20Sopenharmony_ci goto out_err; /* not enough memory */ 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* disable STI PCI ROM. ROM and card RAM overlap and 9198c2ecf20Sopenharmony_ci * leaving it enabled would force HPMCs 9208c2ecf20Sopenharmony_ci */ 9218c2ecf20Sopenharmony_ci if (sti->pd) { 9228c2ecf20Sopenharmony_ci unsigned long rom_base; 9238c2ecf20Sopenharmony_ci rom_base = pci_resource_start(sti->pd, PCI_ROM_RESOURCE); 9248c2ecf20Sopenharmony_ci pci_write_config_dword(sti->pd, PCI_ROM_ADDRESS, rom_base & ~PCI_ROM_ADDRESS_ENABLE); 9258c2ecf20Sopenharmony_ci pr_debug("STI PCI ROM disabled\n"); 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (sti_init_graph(sti)) 9298c2ecf20Sopenharmony_ci goto out_err; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci sti_inq_conf(sti); 9328c2ecf20Sopenharmony_ci sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request); 9338c2ecf20Sopenharmony_ci sti_dump_outptr(sti); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci pr_info(" graphics card name: %s\n", 9368c2ecf20Sopenharmony_ci sti->sti_data->inq_outptr.dev_name); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci sti_roms[num_sti_roms] = sti; 9398c2ecf20Sopenharmony_ci num_sti_roms++; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci return sti; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ciout_err: 9448c2ecf20Sopenharmony_ci kfree(sti); 9458c2ecf20Sopenharmony_ci return NULL; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic void sticore_check_for_default_sti(struct sti_struct *sti, char *path) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci pr_info(" located at [%s]\n", sti->pa_path); 9518c2ecf20Sopenharmony_ci if (strcmp (path, default_sti_path) == 0) 9528c2ecf20Sopenharmony_ci default_sti = sti; 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci/* 9568c2ecf20Sopenharmony_ci * on newer systems PDC gives the address of the ROM 9578c2ecf20Sopenharmony_ci * in the additional address field addr[1] while on 9588c2ecf20Sopenharmony_ci * older Systems the PDC stores it in page0->proc_sti 9598c2ecf20Sopenharmony_ci */ 9608c2ecf20Sopenharmony_cistatic int __init sticore_pa_init(struct parisc_device *dev) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct sti_struct *sti = NULL; 9638c2ecf20Sopenharmony_ci int hpa = dev->hpa.start; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (dev->num_addrs && dev->addr[0]) 9668c2ecf20Sopenharmony_ci sti = sti_try_rom_generic(dev->addr[0], hpa, NULL); 9678c2ecf20Sopenharmony_ci if (!sti) 9688c2ecf20Sopenharmony_ci sti = sti_try_rom_generic(hpa, hpa, NULL); 9698c2ecf20Sopenharmony_ci if (!sti) 9708c2ecf20Sopenharmony_ci sti = sti_try_rom_generic(PAGE0->proc_sti, hpa, NULL); 9718c2ecf20Sopenharmony_ci if (!sti) 9728c2ecf20Sopenharmony_ci return 1; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci print_pa_hwpath(dev, sti->pa_path); 9758c2ecf20Sopenharmony_ci sticore_check_for_default_sti(sti, sti->pa_path); 9768c2ecf20Sopenharmony_ci return 0; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic int sticore_pci_init(struct pci_dev *pd, const struct pci_device_id *ent) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 9838c2ecf20Sopenharmony_ci unsigned long fb_base, rom_base; 9848c2ecf20Sopenharmony_ci unsigned int fb_len, rom_len; 9858c2ecf20Sopenharmony_ci int err; 9868c2ecf20Sopenharmony_ci struct sti_struct *sti; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci err = pci_enable_device(pd); 9898c2ecf20Sopenharmony_ci if (err < 0) { 9908c2ecf20Sopenharmony_ci dev_err(&pd->dev, "Cannot enable PCI device\n"); 9918c2ecf20Sopenharmony_ci return err; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci fb_base = pci_resource_start(pd, 0); 9958c2ecf20Sopenharmony_ci fb_len = pci_resource_len(pd, 0); 9968c2ecf20Sopenharmony_ci rom_base = pci_resource_start(pd, PCI_ROM_RESOURCE); 9978c2ecf20Sopenharmony_ci rom_len = pci_resource_len(pd, PCI_ROM_RESOURCE); 9988c2ecf20Sopenharmony_ci if (rom_base) { 9998c2ecf20Sopenharmony_ci pci_write_config_dword(pd, PCI_ROM_ADDRESS, rom_base | PCI_ROM_ADDRESS_ENABLE); 10008c2ecf20Sopenharmony_ci pr_debug("STI PCI ROM enabled at 0x%08lx\n", rom_base); 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci pr_info("STI PCI graphic ROM found at %08lx (%u kB), fb at %08lx (%u MB)\n", 10048c2ecf20Sopenharmony_ci rom_base, rom_len/1024, fb_base, fb_len/1024/1024); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci pr_debug("Trying PCI STI ROM at %08lx, PCI hpa at %08lx\n", 10078c2ecf20Sopenharmony_ci rom_base, fb_base); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci sti = sti_try_rom_generic(rom_base, fb_base, pd); 10108c2ecf20Sopenharmony_ci if (sti) { 10118c2ecf20Sopenharmony_ci print_pci_hwpath(pd, sti->pa_path); 10128c2ecf20Sopenharmony_ci sticore_check_for_default_sti(sti, sti->pa_path); 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (!sti) { 10168c2ecf20Sopenharmony_ci pr_warn("Unable to handle STI device '%s'\n", pci_name(pd)); 10178c2ecf20Sopenharmony_ci return -ENODEV; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci return 0; 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cistatic void __exit sticore_pci_remove(struct pci_dev *pd) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci BUG(); 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic struct pci_device_id sti_pci_tbl[] = { 10328c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_EG) }, 10338c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX6) }, 10348c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX4) }, 10358c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX2) }, 10368c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FXE) }, 10378c2ecf20Sopenharmony_ci { 0, } /* terminate list */ 10388c2ecf20Sopenharmony_ci}; 10398c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, sti_pci_tbl); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic struct pci_driver pci_sti_driver = { 10428c2ecf20Sopenharmony_ci .name = "sti", 10438c2ecf20Sopenharmony_ci .id_table = sti_pci_tbl, 10448c2ecf20Sopenharmony_ci .probe = sticore_pci_init, 10458c2ecf20Sopenharmony_ci .remove = __exit_p(sticore_pci_remove), 10468c2ecf20Sopenharmony_ci}; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_cistatic struct parisc_device_id sti_pa_tbl[] = { 10498c2ecf20Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00077 }, 10508c2ecf20Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00085 }, 10518c2ecf20Sopenharmony_ci { 0, } 10528c2ecf20Sopenharmony_ci}; 10538c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(parisc, sti_pa_tbl); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_cistatic struct parisc_driver pa_sti_driver __refdata = { 10568c2ecf20Sopenharmony_ci .name = "sti", 10578c2ecf20Sopenharmony_ci .id_table = sti_pa_tbl, 10588c2ecf20Sopenharmony_ci .probe = sticore_pa_init, 10598c2ecf20Sopenharmony_ci}; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci/* 10638c2ecf20Sopenharmony_ci * sti_init_roms() - detects all STI ROMs and stores them in sti_roms[] 10648c2ecf20Sopenharmony_ci */ 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cistatic int sticore_initialized __read_mostly; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic void sti_init_roms(void) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci if (sticore_initialized) 10718c2ecf20Sopenharmony_ci return; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci sticore_initialized = 1; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci pr_info("STI GSC/PCI core graphics driver " 10768c2ecf20Sopenharmony_ci STI_DRIVERVERSION "\n"); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci /* Register drivers for native & PCI cards */ 10798c2ecf20Sopenharmony_ci register_parisc_driver(&pa_sti_driver); 10808c2ecf20Sopenharmony_ci WARN_ON(pci_register_driver(&pci_sti_driver)); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* if we didn't find the given default sti, take the first one */ 10838c2ecf20Sopenharmony_ci if (!default_sti) 10848c2ecf20Sopenharmony_ci default_sti = sti_roms[0]; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci/* 10898c2ecf20Sopenharmony_ci * index = 0 gives default sti 10908c2ecf20Sopenharmony_ci * index > 0 gives other stis in detection order 10918c2ecf20Sopenharmony_ci */ 10928c2ecf20Sopenharmony_cistruct sti_struct * sti_get_rom(unsigned int index) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci if (!sticore_initialized) 10958c2ecf20Sopenharmony_ci sti_init_roms(); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (index == 0) 10988c2ecf20Sopenharmony_ci return default_sti; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci if (index > num_sti_roms) 11018c2ecf20Sopenharmony_ci return NULL; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci return sti_roms[index-1]; 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sti_get_rom); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ciint sti_call(const struct sti_struct *sti, unsigned long func, 11098c2ecf20Sopenharmony_ci const void *flags, void *inptr, void *outptr, 11108c2ecf20Sopenharmony_ci struct sti_glob_cfg *glob_cfg) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci unsigned long _flags = STI_PTR(flags); 11138c2ecf20Sopenharmony_ci unsigned long _inptr = STI_PTR(inptr); 11148c2ecf20Sopenharmony_ci unsigned long _outptr = STI_PTR(outptr); 11158c2ecf20Sopenharmony_ci unsigned long _glob_cfg = STI_PTR(glob_cfg); 11168c2ecf20Sopenharmony_ci int ret; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 11198c2ecf20Sopenharmony_ci /* Check for overflow when using 32bit STI on 64bit kernel. */ 11208c2ecf20Sopenharmony_ci if (WARN_ONCE(_flags>>32 || _inptr>>32 || _outptr>>32 || _glob_cfg>>32, 11218c2ecf20Sopenharmony_ci "Out of 32bit-range pointers!")) 11228c2ecf20Sopenharmony_ci return -1; 11238c2ecf20Sopenharmony_ci#endif 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci ret = pdc_sti_call(func, _flags, _inptr, _outptr, _glob_cfg); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci return ret; 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_STI) 11318c2ecf20Sopenharmony_ci/* check if given fb_info is the primary device */ 11328c2ecf20Sopenharmony_ciint fb_is_primary_device(struct fb_info *info) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci struct sti_struct *sti; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci sti = sti_get_rom(0); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci /* if no built-in graphics card found, allow any fb driver as default */ 11398c2ecf20Sopenharmony_ci if (!sti) 11408c2ecf20Sopenharmony_ci return true; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* return true if it's the default built-in framebuffer driver */ 11438c2ecf20Sopenharmony_ci return (sti->info == info); 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fb_is_primary_device); 11468c2ecf20Sopenharmony_ci#endif 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Philipp Rumpf, Helge Deller, Thomas Bogendoerfer"); 11498c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Core STI driver for HP's NGLE series graphics cards in HP PARISC machines"); 11508c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 11518c2ecf20Sopenharmony_ci 1152