Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * the ISA Virtual Support Module of AMD CS5536
0004  *
0005  * Copyright (C) 2007 Lemote, Inc.
0006  * Author : jlliu, liujl@lemote.com
0007  *
0008  * Copyright (C) 2009 Lemote, Inc.
0009  * Author: Wu Zhangjin, wuzhangjin@gmail.com
0010  */
0011 
0012 #include <linux/pci.h>
0013 #include <cs5536/cs5536.h>
0014 #include <cs5536/cs5536_pci.h>
0015 
0016 /* common variables for PCI_ISA_READ/WRITE_BAR */
0017 static const u32 divil_msr_reg[6] = {
0018     DIVIL_MSR_REG(DIVIL_LBAR_SMB), DIVIL_MSR_REG(DIVIL_LBAR_GPIO),
0019     DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), DIVIL_MSR_REG(DIVIL_LBAR_IRQ),
0020     DIVIL_MSR_REG(DIVIL_LBAR_PMS), DIVIL_MSR_REG(DIVIL_LBAR_ACPI),
0021 };
0022 
0023 static const u32 soft_bar_flag[6] = {
0024     SOFT_BAR_SMB_FLAG, SOFT_BAR_GPIO_FLAG, SOFT_BAR_MFGPT_FLAG,
0025     SOFT_BAR_IRQ_FLAG, SOFT_BAR_PMS_FLAG, SOFT_BAR_ACPI_FLAG,
0026 };
0027 
0028 static const u32 sb_msr_reg[6] = {
0029     SB_MSR_REG(SB_R0), SB_MSR_REG(SB_R1), SB_MSR_REG(SB_R2),
0030     SB_MSR_REG(SB_R3), SB_MSR_REG(SB_R4), SB_MSR_REG(SB_R5),
0031 };
0032 
0033 static const u32 bar_space_range[6] = {
0034     CS5536_SMB_RANGE, CS5536_GPIO_RANGE, CS5536_MFGPT_RANGE,
0035     CS5536_IRQ_RANGE, CS5536_PMS_RANGE, CS5536_ACPI_RANGE,
0036 };
0037 
0038 static const int bar_space_len[6] = {
0039     CS5536_SMB_LENGTH, CS5536_GPIO_LENGTH, CS5536_MFGPT_LENGTH,
0040     CS5536_IRQ_LENGTH, CS5536_PMS_LENGTH, CS5536_ACPI_LENGTH,
0041 };
0042 
0043 /*
0044  * enable the divil module bar space.
0045  *
0046  * For all the DIVIL module LBAR, you should control the DIVIL LBAR reg
0047  * and the RCONFx(0~5) reg to use the modules.
0048  */
0049 static void divil_lbar_enable(void)
0050 {
0051     u32 hi, lo;
0052     int offset;
0053 
0054     /*
0055      * The DIVIL IRQ is not used yet. and make the RCONF0 reserved.
0056      */
0057 
0058     for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
0059         _rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
0060         hi |= 0x01;
0061         _wrmsr(DIVIL_MSR_REG(offset), hi, lo);
0062     }
0063 }
0064 
0065 /*
0066  * disable the divil module bar space.
0067  */
0068 static void divil_lbar_disable(void)
0069 {
0070     u32 hi, lo;
0071     int offset;
0072 
0073     for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
0074         _rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
0075         hi &= ~0x01;
0076         _wrmsr(DIVIL_MSR_REG(offset), hi, lo);
0077     }
0078 }
0079 
0080 /*
0081  * BAR write: write value to the n BAR
0082  */
0083 
0084 void pci_isa_write_bar(int n, u32 value)
0085 {
0086     u32 hi = 0, lo = value;
0087 
0088     if (value == PCI_BAR_RANGE_MASK) {
0089         _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
0090         lo |= soft_bar_flag[n];
0091         _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
0092     } else if (value & 0x01) {
0093         /* NATIVE reg */
0094         hi = 0x0000f001;
0095         lo &= bar_space_range[n];
0096         _wrmsr(divil_msr_reg[n], hi, lo);
0097 
0098         /* RCONFx is 4bytes in units for I/O space */
0099         hi = ((value & 0x000ffffc) << 12) |
0100             ((bar_space_len[n] - 4) << 12) | 0x01;
0101         lo = ((value & 0x000ffffc) << 12) | 0x01;
0102         _wrmsr(sb_msr_reg[n], hi, lo);
0103     }
0104 }
0105 
0106 /*
0107  * BAR read: read the n BAR
0108  */
0109 
0110 u32 pci_isa_read_bar(int n)
0111 {
0112     u32 conf_data = 0;
0113     u32 hi, lo;
0114 
0115     _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
0116     if (lo & soft_bar_flag[n]) {
0117         conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
0118         lo &= ~soft_bar_flag[n];
0119         _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
0120     } else {
0121         _rdmsr(divil_msr_reg[n], &hi, &lo);
0122         conf_data = lo & bar_space_range[n];
0123         conf_data |= 0x01;
0124         conf_data &= ~0x02;
0125     }
0126     return conf_data;
0127 }
0128 
0129 /*
0130  * isa_write: ISA write transfer
0131  *
0132  * We assume that this is not a bus master transfer.
0133  */
0134 void pci_isa_write_reg(int reg, u32 value)
0135 {
0136     u32 hi = 0, lo = value;
0137     u32 temp;
0138 
0139     switch (reg) {
0140     case PCI_COMMAND:
0141         if (value & PCI_COMMAND_IO)
0142             divil_lbar_enable();
0143         else
0144             divil_lbar_disable();
0145         break;
0146     case PCI_STATUS:
0147         _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
0148         temp = lo & 0x0000ffff;
0149         if ((value & PCI_STATUS_SIG_TARGET_ABORT) &&
0150             (lo & SB_TAS_ERR_EN))
0151             temp |= SB_TAS_ERR_FLAG;
0152 
0153         if ((value & PCI_STATUS_REC_TARGET_ABORT) &&
0154             (lo & SB_TAR_ERR_EN))
0155             temp |= SB_TAR_ERR_FLAG;
0156 
0157         if ((value & PCI_STATUS_REC_MASTER_ABORT)
0158             && (lo & SB_MAR_ERR_EN))
0159             temp |= SB_MAR_ERR_FLAG;
0160 
0161         if ((value & PCI_STATUS_DETECTED_PARITY)
0162             && (lo & SB_PARE_ERR_EN))
0163             temp |= SB_PARE_ERR_FLAG;
0164 
0165         lo = temp;
0166         _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
0167         break;
0168     case PCI_CACHE_LINE_SIZE:
0169         value &= 0x0000ff00;
0170         _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
0171         hi &= 0xffffff00;
0172         hi |= (value >> 8);
0173         _wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
0174         break;
0175     case PCI_BAR0_REG:
0176         pci_isa_write_bar(0, value);
0177         break;
0178     case PCI_BAR1_REG:
0179         pci_isa_write_bar(1, value);
0180         break;
0181     case PCI_BAR2_REG:
0182         pci_isa_write_bar(2, value);
0183         break;
0184     case PCI_BAR3_REG:
0185         pci_isa_write_bar(3, value);
0186         break;
0187     case PCI_BAR4_REG:
0188         pci_isa_write_bar(4, value);
0189         break;
0190     case PCI_BAR5_REG:
0191         pci_isa_write_bar(5, value);
0192         break;
0193     case PCI_UART1_INT_REG:
0194         _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
0195         /* disable uart1 interrupt in PIC */
0196         lo &= ~(0xf << 24);
0197         if (value)  /* enable uart1 interrupt in PIC */
0198             lo |= (CS5536_UART1_INTR << 24);
0199         _wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
0200         break;
0201     case PCI_UART2_INT_REG:
0202         _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
0203         /* disable uart2 interrupt in PIC */
0204         lo &= ~(0xf << 28);
0205         if (value)  /* enable uart2 interrupt in PIC */
0206             lo |= (CS5536_UART2_INTR << 28);
0207         _wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
0208         break;
0209     case PCI_ISA_FIXUP_REG:
0210         if (value) {
0211             /* enable the TARGET ABORT/MASTER ABORT etc. */
0212             _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
0213             lo |= 0x00000063;
0214             _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
0215         }
0216 
0217     default:
0218         /* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */
0219         break;
0220     }
0221 }
0222 
0223 /*
0224  * isa_read: ISA read transfers
0225  *
0226  * We assume that this is not a bus master transfer.
0227  */
0228 u32 pci_isa_read_reg(int reg)
0229 {
0230     u32 conf_data = 0;
0231     u32 hi, lo;
0232 
0233     switch (reg) {
0234     case PCI_VENDOR_ID:
0235         conf_data =
0236             CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID);
0237         break;
0238     case PCI_COMMAND:
0239         /* we just check the first LBAR for the IO enable bit, */
0240         /* maybe we should changed later. */
0241         _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);
0242         if (hi & 0x01)
0243             conf_data |= PCI_COMMAND_IO;
0244         break;
0245     case PCI_STATUS:
0246         conf_data |= PCI_STATUS_66MHZ;
0247         conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
0248         conf_data |= PCI_STATUS_FAST_BACK;
0249 
0250         _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
0251         if (lo & SB_TAS_ERR_FLAG)
0252             conf_data |= PCI_STATUS_SIG_TARGET_ABORT;
0253         if (lo & SB_TAR_ERR_FLAG)
0254             conf_data |= PCI_STATUS_REC_TARGET_ABORT;
0255         if (lo & SB_MAR_ERR_FLAG)
0256             conf_data |= PCI_STATUS_REC_MASTER_ABORT;
0257         if (lo & SB_PARE_ERR_FLAG)
0258             conf_data |= PCI_STATUS_DETECTED_PARITY;
0259         break;
0260     case PCI_CLASS_REVISION:
0261         _rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo);
0262         conf_data = lo & 0x000000ff;
0263         conf_data |= (CS5536_ISA_CLASS_CODE << 8);
0264         break;
0265     case PCI_CACHE_LINE_SIZE:
0266         _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
0267         hi &= 0x000000f8;
0268         conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
0269         break;
0270         /*
0271          * we only use the LBAR of DIVIL, no RCONF used.
0272          * all of them are IO space.
0273          */
0274     case PCI_BAR0_REG:
0275         return pci_isa_read_bar(0);
0276         break;
0277     case PCI_BAR1_REG:
0278         return pci_isa_read_bar(1);
0279         break;
0280     case PCI_BAR2_REG:
0281         return pci_isa_read_bar(2);
0282         break;
0283     case PCI_BAR3_REG:
0284         break;
0285     case PCI_BAR4_REG:
0286         return pci_isa_read_bar(4);
0287         break;
0288     case PCI_BAR5_REG:
0289         return pci_isa_read_bar(5);
0290         break;
0291     case PCI_CARDBUS_CIS:
0292         conf_data = PCI_CARDBUS_CIS_POINTER;
0293         break;
0294     case PCI_SUBSYSTEM_VENDOR_ID:
0295         conf_data =
0296             CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID);
0297         break;
0298     case PCI_ROM_ADDRESS:
0299         conf_data = PCI_EXPANSION_ROM_BAR;
0300         break;
0301     case PCI_CAPABILITY_LIST:
0302         conf_data = PCI_CAPLIST_POINTER;
0303         break;
0304     case PCI_INTERRUPT_LINE:
0305         /* no interrupt used here */
0306         conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
0307         break;
0308     default:
0309         break;
0310     }
0311 
0312     return conf_data;
0313 }
0314 
0315 /*
0316  * The mfgpt timer interrupt is running early, so we must keep the south bridge
0317  * mmio always enabled. Otherwise we may race with the PCI configuration which
0318  * may temporarily disable it. When that happens and the timer interrupt fires,
0319  * we are not able to clear it and the system will hang.
0320  */
0321 static void cs5536_isa_mmio_always_on(struct pci_dev *dev)
0322 {
0323     dev->mmio_always_on = 1;
0324 }
0325 DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
0326     PCI_CLASS_BRIDGE_ISA, 8, cs5536_isa_mmio_always_on);