root/arch/mips/loongson64/common/cs5536/cs5536_isa.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. divil_lbar_enable
  2. divil_lbar_disable
  3. pci_isa_write_bar
  4. pci_isa_read_bar
  5. pci_isa_write_reg
  6. pci_isa_read_reg
  7. cs5536_isa_mmio_always_on

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * the ISA Virtual Support Module of AMD CS5536
   4  *
   5  * Copyright (C) 2007 Lemote, Inc.
   6  * Author : jlliu, liujl@lemote.com
   7  *
   8  * Copyright (C) 2009 Lemote, Inc.
   9  * Author: Wu Zhangjin, wuzhangjin@gmail.com
  10  */
  11 
  12 #include <linux/pci.h>
  13 #include <cs5536/cs5536.h>
  14 #include <cs5536/cs5536_pci.h>
  15 
  16 /* common variables for PCI_ISA_READ/WRITE_BAR */
  17 static const u32 divil_msr_reg[6] = {
  18         DIVIL_MSR_REG(DIVIL_LBAR_SMB), DIVIL_MSR_REG(DIVIL_LBAR_GPIO),
  19         DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), DIVIL_MSR_REG(DIVIL_LBAR_IRQ),
  20         DIVIL_MSR_REG(DIVIL_LBAR_PMS), DIVIL_MSR_REG(DIVIL_LBAR_ACPI),
  21 };
  22 
  23 static const u32 soft_bar_flag[6] = {
  24         SOFT_BAR_SMB_FLAG, SOFT_BAR_GPIO_FLAG, SOFT_BAR_MFGPT_FLAG,
  25         SOFT_BAR_IRQ_FLAG, SOFT_BAR_PMS_FLAG, SOFT_BAR_ACPI_FLAG,
  26 };
  27 
  28 static const u32 sb_msr_reg[6] = {
  29         SB_MSR_REG(SB_R0), SB_MSR_REG(SB_R1), SB_MSR_REG(SB_R2),
  30         SB_MSR_REG(SB_R3), SB_MSR_REG(SB_R4), SB_MSR_REG(SB_R5),
  31 };
  32 
  33 static const u32 bar_space_range[6] = {
  34         CS5536_SMB_RANGE, CS5536_GPIO_RANGE, CS5536_MFGPT_RANGE,
  35         CS5536_IRQ_RANGE, CS5536_PMS_RANGE, CS5536_ACPI_RANGE,
  36 };
  37 
  38 static const int bar_space_len[6] = {
  39         CS5536_SMB_LENGTH, CS5536_GPIO_LENGTH, CS5536_MFGPT_LENGTH,
  40         CS5536_IRQ_LENGTH, CS5536_PMS_LENGTH, CS5536_ACPI_LENGTH,
  41 };
  42 
  43 /*
  44  * enable the divil module bar space.
  45  *
  46  * For all the DIVIL module LBAR, you should control the DIVIL LBAR reg
  47  * and the RCONFx(0~5) reg to use the modules.
  48  */
  49 static void divil_lbar_enable(void)
  50 {
  51         u32 hi, lo;
  52         int offset;
  53 
  54         /*
  55          * The DIVIL IRQ is not used yet. and make the RCONF0 reserved.
  56          */
  57 
  58         for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
  59                 _rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
  60                 hi |= 0x01;
  61                 _wrmsr(DIVIL_MSR_REG(offset), hi, lo);
  62         }
  63 }
  64 
  65 /*
  66  * disable the divil module bar space.
  67  */
  68 static void divil_lbar_disable(void)
  69 {
  70         u32 hi, lo;
  71         int offset;
  72 
  73         for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
  74                 _rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
  75                 hi &= ~0x01;
  76                 _wrmsr(DIVIL_MSR_REG(offset), hi, lo);
  77         }
  78 }
  79 
  80 /*
  81  * BAR write: write value to the n BAR
  82  */
  83 
  84 void pci_isa_write_bar(int n, u32 value)
  85 {
  86         u32 hi = 0, lo = value;
  87 
  88         if (value == PCI_BAR_RANGE_MASK) {
  89                 _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
  90                 lo |= soft_bar_flag[n];
  91                 _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
  92         } else if (value & 0x01) {
  93                 /* NATIVE reg */
  94                 hi = 0x0000f001;
  95                 lo &= bar_space_range[n];
  96                 _wrmsr(divil_msr_reg[n], hi, lo);
  97 
  98                 /* RCONFx is 4bytes in units for I/O space */
  99                 hi = ((value & 0x000ffffc) << 12) |
 100                     ((bar_space_len[n] - 4) << 12) | 0x01;
 101                 lo = ((value & 0x000ffffc) << 12) | 0x01;
 102                 _wrmsr(sb_msr_reg[n], hi, lo);
 103         }
 104 }
 105 
 106 /*
 107  * BAR read: read the n BAR
 108  */
 109 
 110 u32 pci_isa_read_bar(int n)
 111 {
 112         u32 conf_data = 0;
 113         u32 hi, lo;
 114 
 115         _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
 116         if (lo & soft_bar_flag[n]) {
 117                 conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
 118                 lo &= ~soft_bar_flag[n];
 119                 _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
 120         } else {
 121                 _rdmsr(divil_msr_reg[n], &hi, &lo);
 122                 conf_data = lo & bar_space_range[n];
 123                 conf_data |= 0x01;
 124                 conf_data &= ~0x02;
 125         }
 126         return conf_data;
 127 }
 128 
 129 /*
 130  * isa_write: ISA write transfer
 131  *
 132  * We assume that this is not a bus master transfer.
 133  */
 134 void pci_isa_write_reg(int reg, u32 value)
 135 {
 136         u32 hi = 0, lo = value;
 137         u32 temp;
 138 
 139         switch (reg) {
 140         case PCI_COMMAND:
 141                 if (value & PCI_COMMAND_IO)
 142                         divil_lbar_enable();
 143                 else
 144                         divil_lbar_disable();
 145                 break;
 146         case PCI_STATUS:
 147                 _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
 148                 temp = lo & 0x0000ffff;
 149                 if ((value & PCI_STATUS_SIG_TARGET_ABORT) &&
 150                     (lo & SB_TAS_ERR_EN))
 151                         temp |= SB_TAS_ERR_FLAG;
 152 
 153                 if ((value & PCI_STATUS_REC_TARGET_ABORT) &&
 154                     (lo & SB_TAR_ERR_EN))
 155                         temp |= SB_TAR_ERR_FLAG;
 156 
 157                 if ((value & PCI_STATUS_REC_MASTER_ABORT)
 158                     && (lo & SB_MAR_ERR_EN))
 159                         temp |= SB_MAR_ERR_FLAG;
 160 
 161                 if ((value & PCI_STATUS_DETECTED_PARITY)
 162                     && (lo & SB_PARE_ERR_EN))
 163                         temp |= SB_PARE_ERR_FLAG;
 164 
 165                 lo = temp;
 166                 _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
 167                 break;
 168         case PCI_CACHE_LINE_SIZE:
 169                 value &= 0x0000ff00;
 170                 _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
 171                 hi &= 0xffffff00;
 172                 hi |= (value >> 8);
 173                 _wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
 174                 break;
 175         case PCI_BAR0_REG:
 176                 pci_isa_write_bar(0, value);
 177                 break;
 178         case PCI_BAR1_REG:
 179                 pci_isa_write_bar(1, value);
 180                 break;
 181         case PCI_BAR2_REG:
 182                 pci_isa_write_bar(2, value);
 183                 break;
 184         case PCI_BAR3_REG:
 185                 pci_isa_write_bar(3, value);
 186                 break;
 187         case PCI_BAR4_REG:
 188                 pci_isa_write_bar(4, value);
 189                 break;
 190         case PCI_BAR5_REG:
 191                 pci_isa_write_bar(5, value);
 192                 break;
 193         case PCI_UART1_INT_REG:
 194                 _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
 195                 /* disable uart1 interrupt in PIC */
 196                 lo &= ~(0xf << 24);
 197                 if (value)      /* enable uart1 interrupt in PIC */
 198                         lo |= (CS5536_UART1_INTR << 24);
 199                 _wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
 200                 break;
 201         case PCI_UART2_INT_REG:
 202                 _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
 203                 /* disable uart2 interrupt in PIC */
 204                 lo &= ~(0xf << 28);
 205                 if (value)      /* enable uart2 interrupt in PIC */
 206                         lo |= (CS5536_UART2_INTR << 28);
 207                 _wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
 208                 break;
 209         case PCI_ISA_FIXUP_REG:
 210                 if (value) {
 211                         /* enable the TARGET ABORT/MASTER ABORT etc. */
 212                         _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
 213                         lo |= 0x00000063;
 214                         _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
 215                 }
 216 
 217         default:
 218                 /* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */
 219                 break;
 220         }
 221 }
 222 
 223 /*
 224  * isa_read: ISA read transfers
 225  *
 226  * We assume that this is not a bus master transfer.
 227  */
 228 u32 pci_isa_read_reg(int reg)
 229 {
 230         u32 conf_data = 0;
 231         u32 hi, lo;
 232 
 233         switch (reg) {
 234         case PCI_VENDOR_ID:
 235                 conf_data =
 236                     CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID);
 237                 break;
 238         case PCI_COMMAND:
 239                 /* we just check the first LBAR for the IO enable bit, */
 240                 /* maybe we should changed later. */
 241                 _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);
 242                 if (hi & 0x01)
 243                         conf_data |= PCI_COMMAND_IO;
 244                 break;
 245         case PCI_STATUS:
 246                 conf_data |= PCI_STATUS_66MHZ;
 247                 conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
 248                 conf_data |= PCI_STATUS_FAST_BACK;
 249 
 250                 _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
 251                 if (lo & SB_TAS_ERR_FLAG)
 252                         conf_data |= PCI_STATUS_SIG_TARGET_ABORT;
 253                 if (lo & SB_TAR_ERR_FLAG)
 254                         conf_data |= PCI_STATUS_REC_TARGET_ABORT;
 255                 if (lo & SB_MAR_ERR_FLAG)
 256                         conf_data |= PCI_STATUS_REC_MASTER_ABORT;
 257                 if (lo & SB_PARE_ERR_FLAG)
 258                         conf_data |= PCI_STATUS_DETECTED_PARITY;
 259                 break;
 260         case PCI_CLASS_REVISION:
 261                 _rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo);
 262                 conf_data = lo & 0x000000ff;
 263                 conf_data |= (CS5536_ISA_CLASS_CODE << 8);
 264                 break;
 265         case PCI_CACHE_LINE_SIZE:
 266                 _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
 267                 hi &= 0x000000f8;
 268                 conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
 269                 break;
 270                 /*
 271                  * we only use the LBAR of DIVIL, no RCONF used.
 272                  * all of them are IO space.
 273                  */
 274         case PCI_BAR0_REG:
 275                 return pci_isa_read_bar(0);
 276                 break;
 277         case PCI_BAR1_REG:
 278                 return pci_isa_read_bar(1);
 279                 break;
 280         case PCI_BAR2_REG:
 281                 return pci_isa_read_bar(2);
 282                 break;
 283         case PCI_BAR3_REG:
 284                 break;
 285         case PCI_BAR4_REG:
 286                 return pci_isa_read_bar(4);
 287                 break;
 288         case PCI_BAR5_REG:
 289                 return pci_isa_read_bar(5);
 290                 break;
 291         case PCI_CARDBUS_CIS:
 292                 conf_data = PCI_CARDBUS_CIS_POINTER;
 293                 break;
 294         case PCI_SUBSYSTEM_VENDOR_ID:
 295                 conf_data =
 296                     CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID);
 297                 break;
 298         case PCI_ROM_ADDRESS:
 299                 conf_data = PCI_EXPANSION_ROM_BAR;
 300                 break;
 301         case PCI_CAPABILITY_LIST:
 302                 conf_data = PCI_CAPLIST_POINTER;
 303                 break;
 304         case PCI_INTERRUPT_LINE:
 305                 /* no interrupt used here */
 306                 conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
 307                 break;
 308         default:
 309                 break;
 310         }
 311 
 312         return conf_data;
 313 }
 314 
 315 /*
 316  * The mfgpt timer interrupt is running early, so we must keep the south bridge
 317  * mmio always enabled. Otherwise we may race with the PCI configuration which
 318  * may temporarily disable it. When that happens and the timer interrupt fires,
 319  * we are not able to clear it and the system will hang.
 320  */
 321 static void cs5536_isa_mmio_always_on(struct pci_dev *dev)
 322 {
 323         dev->mmio_always_on = 1;
 324 }
 325 DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
 326         PCI_CLASS_BRIDGE_ISA, 8, cs5536_isa_mmio_always_on);

/* [<][>][^][v][top][bottom][index][help] */