Path: blob/master/arch/mips/loongson/common/cs5536/cs5536_isa.c
10820 views
/*1* the ISA Virtual Support Module of AMD CS55362*3* Copyright (C) 2007 Lemote, Inc.4* Author : jlliu, [email protected]5*6* Copyright (C) 2009 Lemote, Inc.7* Author: Wu Zhangjin, [email protected]8*9* This program is free software; you can redistribute it and/or modify it10* under the terms of the GNU General Public License as published by the11* Free Software Foundation; either version 2 of the License, or (at your12* option) any later version.13*/1415#include <cs5536/cs5536.h>16#include <cs5536/cs5536_pci.h>1718/* common variables for PCI_ISA_READ/WRITE_BAR */19static const u32 divil_msr_reg[6] = {20DIVIL_MSR_REG(DIVIL_LBAR_SMB), DIVIL_MSR_REG(DIVIL_LBAR_GPIO),21DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), DIVIL_MSR_REG(DIVIL_LBAR_IRQ),22DIVIL_MSR_REG(DIVIL_LBAR_PMS), DIVIL_MSR_REG(DIVIL_LBAR_ACPI),23};2425static const u32 soft_bar_flag[6] = {26SOFT_BAR_SMB_FLAG, SOFT_BAR_GPIO_FLAG, SOFT_BAR_MFGPT_FLAG,27SOFT_BAR_IRQ_FLAG, SOFT_BAR_PMS_FLAG, SOFT_BAR_ACPI_FLAG,28};2930static const u32 sb_msr_reg[6] = {31SB_MSR_REG(SB_R0), SB_MSR_REG(SB_R1), SB_MSR_REG(SB_R2),32SB_MSR_REG(SB_R3), SB_MSR_REG(SB_R4), SB_MSR_REG(SB_R5),33};3435static const u32 bar_space_range[6] = {36CS5536_SMB_RANGE, CS5536_GPIO_RANGE, CS5536_MFGPT_RANGE,37CS5536_IRQ_RANGE, CS5536_PMS_RANGE, CS5536_ACPI_RANGE,38};3940static const int bar_space_len[6] = {41CS5536_SMB_LENGTH, CS5536_GPIO_LENGTH, CS5536_MFGPT_LENGTH,42CS5536_IRQ_LENGTH, CS5536_PMS_LENGTH, CS5536_ACPI_LENGTH,43};4445/*46* enable the divil module bar space.47*48* For all the DIVIL module LBAR, you should control the DIVIL LBAR reg49* and the RCONFx(0~5) reg to use the modules.50*/51static void divil_lbar_enable(void)52{53u32 hi, lo;54int offset;5556/*57* The DIVIL IRQ is not used yet. and make the RCONF0 reserved.58*/5960for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {61_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);62hi |= 0x01;63_wrmsr(DIVIL_MSR_REG(offset), hi, lo);64}65}6667/*68* disable the divil module bar space.69*/70static void divil_lbar_disable(void)71{72u32 hi, lo;73int offset;7475for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {76_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);77hi &= ~0x01;78_wrmsr(DIVIL_MSR_REG(offset), hi, lo);79}80}8182/*83* BAR write: write value to the n BAR84*/8586void pci_isa_write_bar(int n, u32 value)87{88u32 hi = 0, lo = value;8990if (value == PCI_BAR_RANGE_MASK) {91_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);92lo |= soft_bar_flag[n];93_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);94} else if (value & 0x01) {95/* NATIVE reg */96hi = 0x0000f001;97lo &= bar_space_range[n];98_wrmsr(divil_msr_reg[n], hi, lo);99100/* RCONFx is 4bytes in units for I/O space */101hi = ((value & 0x000ffffc) << 12) |102((bar_space_len[n] - 4) << 12) | 0x01;103lo = ((value & 0x000ffffc) << 12) | 0x01;104_wrmsr(sb_msr_reg[n], hi, lo);105}106}107108/*109* BAR read: read the n BAR110*/111112u32 pci_isa_read_bar(int n)113{114u32 conf_data = 0;115u32 hi, lo;116117_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);118if (lo & soft_bar_flag[n]) {119conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;120lo &= ~soft_bar_flag[n];121_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);122} else {123_rdmsr(divil_msr_reg[n], &hi, &lo);124conf_data = lo & bar_space_range[n];125conf_data |= 0x01;126conf_data &= ~0x02;127}128return conf_data;129}130131/*132* isa_write: ISA write transfer133*134* We assume that this is not a bus master transfer.135*/136void pci_isa_write_reg(int reg, u32 value)137{138u32 hi = 0, lo = value;139u32 temp;140141switch (reg) {142case PCI_COMMAND:143if (value & PCI_COMMAND_IO)144divil_lbar_enable();145else146divil_lbar_disable();147break;148case PCI_STATUS:149_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);150temp = lo & 0x0000ffff;151if ((value & PCI_STATUS_SIG_TARGET_ABORT) &&152(lo & SB_TAS_ERR_EN))153temp |= SB_TAS_ERR_FLAG;154155if ((value & PCI_STATUS_REC_TARGET_ABORT) &&156(lo & SB_TAR_ERR_EN))157temp |= SB_TAR_ERR_FLAG;158159if ((value & PCI_STATUS_REC_MASTER_ABORT)160&& (lo & SB_MAR_ERR_EN))161temp |= SB_MAR_ERR_FLAG;162163if ((value & PCI_STATUS_DETECTED_PARITY)164&& (lo & SB_PARE_ERR_EN))165temp |= SB_PARE_ERR_FLAG;166167lo = temp;168_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);169break;170case PCI_CACHE_LINE_SIZE:171value &= 0x0000ff00;172_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);173hi &= 0xffffff00;174hi |= (value >> 8);175_wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);176break;177case PCI_BAR0_REG:178pci_isa_write_bar(0, value);179break;180case PCI_BAR1_REG:181pci_isa_write_bar(1, value);182break;183case PCI_BAR2_REG:184pci_isa_write_bar(2, value);185break;186case PCI_BAR3_REG:187pci_isa_write_bar(3, value);188break;189case PCI_BAR4_REG:190pci_isa_write_bar(4, value);191break;192case PCI_BAR5_REG:193pci_isa_write_bar(5, value);194break;195case PCI_UART1_INT_REG:196_rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);197/* disable uart1 interrupt in PIC */198lo &= ~(0xf << 24);199if (value) /* enable uart1 interrupt in PIC */200lo |= (CS5536_UART1_INTR << 24);201_wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);202break;203case PCI_UART2_INT_REG:204_rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);205/* disable uart2 interrupt in PIC */206lo &= ~(0xf << 28);207if (value) /* enable uart2 interrupt in PIC */208lo |= (CS5536_UART2_INTR << 28);209_wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);210break;211case PCI_ISA_FIXUP_REG:212if (value) {213/* enable the TARGET ABORT/MASTER ABORT etc. */214_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);215lo |= 0x00000063;216_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);217}218219default:220/* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */221break;222}223}224225/*226* isa_read: ISA read transfers227*228* We assume that this is not a bus master transfer.229*/230u32 pci_isa_read_reg(int reg)231{232u32 conf_data = 0;233u32 hi, lo;234235switch (reg) {236case PCI_VENDOR_ID:237conf_data =238CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID);239break;240case PCI_COMMAND:241/* we just check the first LBAR for the IO enable bit, */242/* maybe we should changed later. */243_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);244if (hi & 0x01)245conf_data |= PCI_COMMAND_IO;246break;247case PCI_STATUS:248conf_data |= PCI_STATUS_66MHZ;249conf_data |= PCI_STATUS_DEVSEL_MEDIUM;250conf_data |= PCI_STATUS_FAST_BACK;251252_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);253if (lo & SB_TAS_ERR_FLAG)254conf_data |= PCI_STATUS_SIG_TARGET_ABORT;255if (lo & SB_TAR_ERR_FLAG)256conf_data |= PCI_STATUS_REC_TARGET_ABORT;257if (lo & SB_MAR_ERR_FLAG)258conf_data |= PCI_STATUS_REC_MASTER_ABORT;259if (lo & SB_PARE_ERR_FLAG)260conf_data |= PCI_STATUS_DETECTED_PARITY;261break;262case PCI_CLASS_REVISION:263_rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo);264conf_data = lo & 0x000000ff;265conf_data |= (CS5536_ISA_CLASS_CODE << 8);266break;267case PCI_CACHE_LINE_SIZE:268_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);269hi &= 0x000000f8;270conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);271break;272/*273* we only use the LBAR of DIVIL, no RCONF used.274* all of them are IO space.275*/276case PCI_BAR0_REG:277return pci_isa_read_bar(0);278break;279case PCI_BAR1_REG:280return pci_isa_read_bar(1);281break;282case PCI_BAR2_REG:283return pci_isa_read_bar(2);284break;285case PCI_BAR3_REG:286break;287case PCI_BAR4_REG:288return pci_isa_read_bar(4);289break;290case PCI_BAR5_REG:291return pci_isa_read_bar(5);292break;293case PCI_CARDBUS_CIS:294conf_data = PCI_CARDBUS_CIS_POINTER;295break;296case PCI_SUBSYSTEM_VENDOR_ID:297conf_data =298CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID);299break;300case PCI_ROM_ADDRESS:301conf_data = PCI_EXPANSION_ROM_BAR;302break;303case PCI_CAPABILITY_LIST:304conf_data = PCI_CAPLIST_POINTER;305break;306case PCI_INTERRUPT_LINE:307/* no interrupt used here */308conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);309break;310default:311break;312}313314return conf_data;315}316317318