M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
@@ -0,0 +1,11 @@
#
# Makefile for CS5536 support.
#
obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \
cs5536_isa.o cs5536_ehci.o
#
# Enable cs5536 mfgpt Timer
#
obj-$(CONFIG_CS5536_MFGPT) += cs5536_mfgpt.o
@@ -0,0 +1,140 @@
/*
* the ACC Virtual Support Module of AMD CS5536
*
* Copyright (C) 2007 Lemote, Inc.
* Author : jlliu, liujl@lemote.com
*
* Copyright (C) 2009 Lemote, Inc.
* Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <cs5536/cs5536.h>
#include <cs5536/cs5536_pci.h>
void pci_acc_write_reg(int reg, u32 value)
{
u32 hi = 0, lo = value;
switch (reg) {
case PCI_COMMAND:
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
if (value & PCI_COMMAND_MASTER)
lo |= (0x03 << 8);
else
lo &= ~(0x03 << 8);
_wrmsr(GLIU_MSR_REG(GLIU_PAE), hi, lo);
break;
case PCI_STATUS:
if (value & PCI_STATUS_PARITY) {
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG) {
lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
}
}
break;
case PCI_BAR0_REG:
if (value == PCI_BAR_RANGE_MASK) {
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
lo |= SOFT_BAR_ACC_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else if (value & 0x01) {
value &= 0xfffffffc;
hi = 0xA0000000 | ((value & 0x000ff000) >> 12);
lo = 0x000fff80 | ((value & 0x00000fff) << 20);
_wrmsr(GLIU_MSR_REG(GLIU_IOD_BM1), hi, lo);
}
break;
case PCI_ACC_INT_REG:
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
/* disable all the usb interrupt in PIC */
lo &= ~(0xf << PIC_YSEL_LOW_ACC_SHIFT);
if (value) /* enable all the acc interrupt in PIC */
lo |= (CS5536_ACC_INTR << PIC_YSEL_LOW_ACC_SHIFT);
_wrmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), hi, lo);
break;
default:
break;
}
}
u32 pci_acc_read_reg(int reg)
{
u32 hi, lo;
u32 conf_data = 0;
switch (reg) {
case PCI_VENDOR_ID:
conf_data =
CFG_PCI_VENDOR_ID(CS5536_ACC_DEVICE_ID, CS5536_VENDOR_ID);
break;
case PCI_COMMAND:
_rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
if (((lo & 0xfff00000) || (hi & 0x000000ff))
&& ((hi & 0xf0000000) == 0xa0000000))
conf_data |= PCI_COMMAND_IO;
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
if ((lo & 0x300) == 0x300)
conf_data |= PCI_COMMAND_MASTER;
break;
case PCI_STATUS:
conf_data |= PCI_STATUS_66MHZ;
conf_data |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
conf_data |= PCI_STATUS_PARITY;
conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(ACC_MSR_REG(ACC_CAP), &hi, &lo);
conf_data = lo & 0x000000ff;
conf_data |= (CS5536_ACC_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
conf_data =
CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
PCI_NORMAL_LATENCY_TIMER);
break;
case PCI_BAR0_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_ACC_FLAG) {
conf_data = CS5536_ACC_RANGE |
PCI_BASE_ADDRESS_SPACE_IO;
lo &= ~SOFT_BAR_ACC_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
conf_data = (hi & 0x000000ff) << 12;
conf_data |= (lo & 0xfff00000) >> 20;
conf_data |= 0x01;
conf_data &= ~0x02;
}
break;
case PCI_CARDBUS_CIS:
conf_data = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_SUBSYSTEM_VENDOR_ID:
conf_data =
CFG_PCI_VENDOR_ID(CS5536_ACC_SUB_ID, CS5536_SUB_VENDOR_ID);
break;
case PCI_ROM_ADDRESS:
conf_data = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
conf_data = PCI_CAPLIST_USB_POINTER;
break;
case PCI_INTERRUPT_LINE:
conf_data =
CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR);
break;
default:
break;
}
return conf_data;
}
@@ -0,0 +1,160 @@
/*
* the EHCI Virtual Support Module of AMD CS5536
*
* Copyright (C) 2007 Lemote, Inc.
* Author : jlliu, liujl@lemote.com
*
* Copyright (C) 2009 Lemote, Inc.
* Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <cs5536/cs5536.h>
#include <cs5536/cs5536_pci.h>
void pci_ehci_write_reg(int reg, u32 value)
{
u32 hi = 0, lo = value;
switch (reg) {
case PCI_COMMAND:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
if (value & PCI_COMMAND_MASTER)
hi |= PCI_COMMAND_MASTER;
else
hi &= ~PCI_COMMAND_MASTER;
if (value & PCI_COMMAND_MEMORY)
hi |= PCI_COMMAND_MEMORY;
else
hi &= ~PCI_COMMAND_MEMORY;
_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
break;
case PCI_STATUS:
if (value & PCI_STATUS_PARITY) {
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG) {
lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
}
}
break;
case PCI_BAR0_REG:
if (value == PCI_BAR_RANGE_MASK) {
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
lo |= SOFT_BAR_EHCI_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else if ((value & 0x01) == 0x00) {
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
lo = value;
_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
value &= 0xfffffff0;
hi = 0x40000000 | ((value & 0xff000000) >> 24);
lo = 0x000fffff | ((value & 0x00fff000) << 8);
_wrmsr(GLIU_MSR_REG(GLIU_P2D_BM4), hi, lo);
}
break;
case PCI_EHCI_LEGSMIEN_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
hi &= 0x003f0000;
hi |= (value & 0x3f) << 16;
_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
break;
case PCI_EHCI_FLADJ_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
hi &= ~0x00003f00;
hi |= value & 0x00003f00;
_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
break;
default:
break;
}
}
u32 pci_ehci_read_reg(int reg)
{
u32 conf_data = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
conf_data =
CFG_PCI_VENDOR_ID(CS5536_EHCI_DEVICE_ID, CS5536_VENDOR_ID);
break;
case PCI_COMMAND:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
if (hi & PCI_COMMAND_MASTER)
conf_data |= PCI_COMMAND_MASTER;
if (hi & PCI_COMMAND_MEMORY)
conf_data |= PCI_COMMAND_MEMORY;
break;
case PCI_STATUS:
conf_data |= PCI_STATUS_66MHZ;
conf_data |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
conf_data |= PCI_STATUS_PARITY;
conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
conf_data = lo & 0x000000ff;
conf_data |= (CS5536_EHCI_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
conf_data =
CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
PCI_NORMAL_LATENCY_TIMER);
break;
case PCI_BAR0_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_EHCI_FLAG) {
conf_data = CS5536_EHCI_RANGE |
PCI_BASE_ADDRESS_SPACE_MEMORY;
lo &= ~SOFT_BAR_EHCI_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
conf_data = lo & 0xfffff000;
}
break;
case PCI_CARDBUS_CIS:
conf_data = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_SUBSYSTEM_VENDOR_ID:
conf_data =
CFG_PCI_VENDOR_ID(CS5536_EHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
break;
case PCI_ROM_ADDRESS:
conf_data = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
conf_data = PCI_CAPLIST_USB_POINTER;
break;
case PCI_INTERRUPT_LINE:
conf_data =
CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
break;
case PCI_EHCI_LEGSMIEN_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
conf_data = (hi & 0x003f0000) >> 16;
break;
case PCI_EHCI_LEGSMISTS_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
conf_data = (hi & 0x3f000000) >> 24;
break;
case PCI_EHCI_FLADJ_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
conf_data = hi & 0x00003f00;
break;
default:
break;
}
return conf_data;
}
@@ -0,0 +1,192 @@
/*
* the IDE Virtual Support Module of AMD CS5536
*
* Copyright (C) 2007 Lemote, Inc.
* Author : jlliu, liujl@lemote.com
*
* Copyright (C) 2009 Lemote, Inc.
* Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <cs5536/cs5536.h>
#include <cs5536/cs5536_pci.h>
void pci_ide_write_reg(int reg, u32 value)
{
u32 hi = 0, lo = value;
switch (reg) {
case PCI_COMMAND:
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
if (value & PCI_COMMAND_MASTER)
lo |= (0x03 << 4);
else
lo &= ~(0x03 << 4);
_wrmsr(GLIU_MSR_REG(GLIU_PAE), hi, lo);
break;
case PCI_STATUS:
if (value & PCI_STATUS_PARITY) {
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG) {
lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
}
}
break;
case PCI_CACHE_LINE_SIZE:
value &= 0x0000ff00;
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
hi &= 0xffffff00;
hi |= (value >> 8);
_wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
break;
case PCI_BAR4_REG:
if (value == PCI_BAR_RANGE_MASK) {
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
lo |= SOFT_BAR_IDE_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else if (value & 0x01) {
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
lo = (value & 0xfffffff0) | 0x1;
_wrmsr(IDE_MSR_REG(IDE_IO_BAR), hi, lo);
value &= 0xfffffffc;
hi = 0x60000000 | ((value & 0x000ff000) >> 12);
lo = 0x000ffff0 | ((value & 0x00000fff) << 20);
_wrmsr(GLIU_MSR_REG(GLIU_IOD_BM2), hi, lo);
}
break;
case PCI_IDE_CFG_REG:
if (value == CS5536_IDE_FLASH_SIGNATURE) {
_rdmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), &hi, &lo);
lo |= 0x01;
_wrmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), hi, lo);
} else {
_rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
lo = value;
_wrmsr(IDE_MSR_REG(IDE_CFG), hi, lo);
}
break;
case PCI_IDE_DTC_REG:
_rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
lo = value;
_wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo);
break;
case PCI_IDE_CAST_REG:
_rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
lo = value;
_wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo);
break;
case PCI_IDE_ETC_REG:
_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
lo = value;
_wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo);
break;
case PCI_IDE_PM_REG:
_rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
lo = value;
_wrmsr(IDE_MSR_REG(IDE_INTERNAL_PM), hi, lo);
break;
default:
break;
}
}
u32 pci_ide_read_reg(int reg)
{
u32 conf_data = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
conf_data =
CFG_PCI_VENDOR_ID(CS5536_IDE_DEVICE_ID, CS5536_VENDOR_ID);
break;
case PCI_COMMAND:
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
if (lo & 0xfffffff0)
conf_data |= PCI_COMMAND_IO;
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
if ((lo & 0x30) == 0x30)
conf_data |= PCI_COMMAND_MASTER;
break;
case PCI_STATUS:
conf_data |= PCI_STATUS_66MHZ;
conf_data |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
conf_data |= PCI_STATUS_PARITY;
conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(IDE_MSR_REG(IDE_CAP), &hi, &lo);
conf_data = lo & 0x000000ff;
conf_data |= (CS5536_IDE_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
hi &= 0x000000f8;
conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi);
break;
case PCI_BAR4_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_IDE_FLAG) {
conf_data = CS5536_IDE_RANGE |
PCI_BASE_ADDRESS_SPACE_IO;
lo &= ~SOFT_BAR_IDE_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
conf_data = lo & 0xfffffff0;
conf_data |= 0x01;
conf_data &= ~0x02;
}
break;
case PCI_CARDBUS_CIS:
conf_data = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_SUBSYSTEM_VENDOR_ID:
conf_data =
CFG_PCI_VENDOR_ID(CS5536_IDE_SUB_ID, CS5536_SUB_VENDOR_ID);
break;
case PCI_ROM_ADDRESS:
conf_data = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
conf_data = PCI_CAPLIST_POINTER;
break;
case PCI_INTERRUPT_LINE:
conf_data =
CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR);
break;
case PCI_IDE_CFG_REG:
_rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
conf_data = lo;
break;
case PCI_IDE_DTC_REG:
_rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
conf_data = lo;
break;
case PCI_IDE_CAST_REG:
_rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
conf_data = lo;
break;
case PCI_IDE_ETC_REG:
_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
conf_data = lo;
break;
case PCI_IDE_PM_REG:
_rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
conf_data = lo;
break;
default:
break;
}
return conf_data;
}
@@ -0,0 +1,316 @@
/*
* the ISA Virtual Support Module of AMD CS5536
*
* Copyright (C) 2007 Lemote, Inc.
* Author : jlliu, liujl@lemote.com
*
* Copyright (C) 2009 Lemote, Inc.
* Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <cs5536/cs5536.h>
#include <cs5536/cs5536_pci.h>
/* common variables for PCI_ISA_READ/WRITE_BAR */
static const u32 divil_msr_reg[6] = {
DIVIL_MSR_REG(DIVIL_LBAR_SMB), DIVIL_MSR_REG(DIVIL_LBAR_GPIO),
DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), DIVIL_MSR_REG(DIVIL_LBAR_IRQ),
DIVIL_MSR_REG(DIVIL_LBAR_PMS), DIVIL_MSR_REG(DIVIL_LBAR_ACPI),
};
static const u32 soft_bar_flag[6] = {
SOFT_BAR_SMB_FLAG, SOFT_BAR_GPIO_FLAG, SOFT_BAR_MFGPT_FLAG,
SOFT_BAR_IRQ_FLAG, SOFT_BAR_PMS_FLAG, SOFT_BAR_ACPI_FLAG,
};
static const u32 sb_msr_reg[6] = {
SB_MSR_REG(SB_R0), SB_MSR_REG(SB_R1), SB_MSR_REG(SB_R2),
SB_MSR_REG(SB_R3), SB_MSR_REG(SB_R4), SB_MSR_REG(SB_R5),
};
static const u32 bar_space_range[6] = {
CS5536_SMB_RANGE, CS5536_GPIO_RANGE, CS5536_MFGPT_RANGE,
CS5536_IRQ_RANGE, CS5536_PMS_RANGE, CS5536_ACPI_RANGE,
};
static const int bar_space_len[6] = {
CS5536_SMB_LENGTH, CS5536_GPIO_LENGTH, CS5536_MFGPT_LENGTH,
CS5536_IRQ_LENGTH, CS5536_PMS_LENGTH, CS5536_ACPI_LENGTH,
};
/*
* enable the divil module bar space.
*
* For all the DIVIL module LBAR, you should control the DIVIL LBAR reg
* and the RCONFx(0~5) reg to use the modules.
*/
static void divil_lbar_enable(void)
{
u32 hi, lo;
int offset;
/*
* The DIVIL IRQ is not used yet. and make the RCONF0 reserved.
*/
for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
hi |= 0x01;
_wrmsr(DIVIL_MSR_REG(offset), hi, lo);
}
}
/*
* disable the divil module bar space.
*/
static void divil_lbar_disable(void)
{
u32 hi, lo;
int offset;
for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
hi &= ~0x01;
_wrmsr(DIVIL_MSR_REG(offset), hi, lo);
}
}
/*
* BAR write: write value to the n BAR
*/
void pci_isa_write_bar(int n, u32 value)
{
u32 hi = 0, lo = value;
if (value == PCI_BAR_RANGE_MASK) {
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
lo |= soft_bar_flag[n];
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else if (value & 0x01) {
/* NATIVE reg */
hi = 0x0000f001;
lo &= bar_space_range[n];
_wrmsr(divil_msr_reg[n], hi, lo);
/* RCONFx is 4bytes in units for I/O space */
hi = ((value & 0x000ffffc) << 12) |
((bar_space_len[n] - 4) << 12) | 0x01;
lo = ((value & 0x000ffffc) << 12) | 0x01;
_wrmsr(sb_msr_reg[n], hi, lo);
}
}
/*
* BAR read: read the n BAR
*/
u32 pci_isa_read_bar(int n)
{
u32 conf_data = 0;
u32 hi, lo;
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & soft_bar_flag[n]) {
conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
lo &= ~soft_bar_flag[n];
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(divil_msr_reg[n], &hi, &lo);
conf_data = lo & bar_space_range[n];
conf_data |= 0x01;
conf_data &= ~0x02;
}
return conf_data;
}
/*
* isa_write: ISA write transfer
*
* We assume that this is not a bus master transfer.
*/
void pci_isa_write_reg(int reg, u32 value)
{
u32 hi = 0, lo = value;
u32 temp;
switch (reg) {
case PCI_COMMAND:
if (value & PCI_COMMAND_IO)
divil_lbar_enable();
else
divil_lbar_disable();
break;
case PCI_STATUS:
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
temp = lo & 0x0000ffff;
if ((value & PCI_STATUS_SIG_TARGET_ABORT) &&
(lo & SB_TAS_ERR_EN))
temp |= SB_TAS_ERR_FLAG;
if ((value & PCI_STATUS_REC_TARGET_ABORT) &&
(lo & SB_TAR_ERR_EN))
temp |= SB_TAR_ERR_FLAG;
if ((value & PCI_STATUS_REC_MASTER_ABORT)
&& (lo & SB_MAR_ERR_EN))
temp |= SB_MAR_ERR_FLAG;
if ((value & PCI_STATUS_DETECTED_PARITY)
&& (lo & SB_PARE_ERR_EN))
temp |= SB_PARE_ERR_FLAG;
lo = temp;
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
break;
case PCI_CACHE_LINE_SIZE:
value &= 0x0000ff00;
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
hi &= 0xffffff00;
hi |= (value >> 8);
_wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
break;
case PCI_BAR0_REG:
pci_isa_write_bar(0, value);
break;
case PCI_BAR1_REG:
pci_isa_write_bar(1, value);
break;
case PCI_BAR2_REG:
pci_isa_write_bar(2, value);
break;
case PCI_BAR3_REG:
pci_isa_write_bar(3, value);
break;
case PCI_BAR4_REG:
pci_isa_write_bar(4, value);
break;
case PCI_BAR5_REG:
pci_isa_write_bar(5, value);
break;
case PCI_UART1_INT_REG:
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
/* disable uart1 interrupt in PIC */
lo &= ~(0xf << 24);
if (value) /* enable uart1 interrupt in PIC */
lo |= (CS5536_UART1_INTR << 24);
_wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
break;
case PCI_UART2_INT_REG:
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
/* disable uart2 interrupt in PIC */
lo &= ~(0xf << 28);
if (value) /* enable uart2 interrupt in PIC */
lo |= (CS5536_UART2_INTR << 28);
_wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
break;
case PCI_ISA_FIXUP_REG:
if (value) {
/* enable the TARGET ABORT/MASTER ABORT etc. */
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
lo |= 0x00000063;
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
}
default:
/* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */
break;
}
}
/*
* isa_read: ISA read transfers
*
* We assume that this is not a bus master transfer.
*/
u32 pci_isa_read_reg(int reg)
{
u32 conf_data = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
conf_data =
CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID);
break;
case PCI_COMMAND:
/* we just check the first LBAR for the IO enable bit, */
/* maybe we should changed later. */
_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);
if (hi & 0x01)
conf_data |= PCI_COMMAND_IO;
break;
case PCI_STATUS:
conf_data |= PCI_STATUS_66MHZ;
conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
conf_data |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_TAS_ERR_FLAG)
conf_data |= PCI_STATUS_SIG_TARGET_ABORT;
if (lo & SB_TAR_ERR_FLAG)
conf_data |= PCI_STATUS_REC_TARGET_ABORT;
if (lo & SB_MAR_ERR_FLAG)
conf_data |= PCI_STATUS_REC_MASTER_ABORT;
if (lo & SB_PARE_ERR_FLAG)
conf_data |= PCI_STATUS_DETECTED_PARITY;
break;
case PCI_CLASS_REVISION:
_rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo);
conf_data = lo & 0x000000ff;
conf_data |= (CS5536_ISA_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
hi &= 0x000000f8;
conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
break;
/*
* we only use the LBAR of DIVIL, no RCONF used.
* all of them are IO space.
*/
case PCI_BAR0_REG:
return pci_isa_read_bar(0);
break;
case PCI_BAR1_REG:
return pci_isa_read_bar(1);
break;
case PCI_BAR2_REG:
return pci_isa_read_bar(2);
break;
case PCI_BAR3_REG:
break;
case PCI_BAR4_REG:
return pci_isa_read_bar(4);
break;
case PCI_BAR5_REG:
return pci_isa_read_bar(5);
break;
case PCI_CARDBUS_CIS:
conf_data = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_SUBSYSTEM_VENDOR_ID:
conf_data =
CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID);
break;
case PCI_ROM_ADDRESS:
conf_data = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
conf_data = PCI_CAPLIST_POINTER;
break;
case PCI_INTERRUPT_LINE:
/* no interrupt used here */
conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
break;
default:
break;
}
return conf_data;
}
@@ -0,0 +1,214 @@
/*
* CS5536 General timer functions
*
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
* Author: Yanhua, yanh@lemote.com
*
* Copyright (C) 2009 Lemote Inc.
* Author: Wu zhangjin, wuzhangjin@gmail.com
*
* Reference: AMD Geode(TM) CS5536 Companion Device Data Book
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/io.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/clockchips.h>
#include <asm/time.h>
#include <cs5536/cs5536_mfgpt.h>
DEFINE_SPINLOCK(mfgpt_lock);
EXPORT_SYMBOL(mfgpt_lock);
static u32 mfgpt_base;
/*
* Initialize the MFGPT timer.
*
* This is also called after resume to bring the MFGPT into operation again.
*/
/* disable counter */
void disable_mfgpt0_counter(void)
{
outw(inw(MFGPT0_SETUP) & 0x7fff, MFGPT0_SETUP);
}
EXPORT_SYMBOL(disable_mfgpt0_counter);
/* enable counter, comparator2 to event mode, 14.318MHz clock */
void enable_mfgpt0_counter(void)
{
outw(0xe310, MFGPT0_SETUP);
}
EXPORT_SYMBOL(enable_mfgpt0_counter);
static void init_mfgpt_timer(enum clock_event_mode mode,
struct clock_event_device *evt)
{
spin_lock(&mfgpt_lock);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */
outw(0, MFGPT0_CNT); /* set counter to 0 */
enable_mfgpt0_counter();
break;
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
evt->mode == CLOCK_EVT_MODE_ONESHOT)
disable_mfgpt0_counter();
break;
case CLOCK_EVT_MODE_ONESHOT:
/* The oneshot mode have very high deviation, Not use it! */
break;
case CLOCK_EVT_MODE_RESUME:
/* Nothing to do here */
break;
}
spin_unlock(&mfgpt_lock);
}
static struct clock_event_device mfgpt_clockevent = {
.name = "mfgpt",
.features = CLOCK_EVT_FEAT_PERIODIC,
.set_mode = init_mfgpt_timer,
.irq = CS5536_MFGPT_INTR,
};
static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
u32 basehi;
/*
* get MFGPT base address
*
* NOTE: do not remove me, it's need for the value of mfgpt_base is
* variable
*/
_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
/* ack */
outw(inw(MFGPT0_SETUP) | 0x4000, MFGPT0_SETUP);
mfgpt_clockevent.event_handler(&mfgpt_clockevent);
return IRQ_HANDLED;
}
static struct irqaction irq5 = {
.handler = timer_interrupt,
.flags = IRQF_NOBALANCING | IRQF_TIMER,
.name = "timer"
};
/*
* Initialize the conversion factor and the min/max deltas of the clock event
* structure and register the clock event source with the framework.
*/
void __init setup_mfgpt0_timer(void)
{
u32 basehi;
struct clock_event_device *cd = &mfgpt_clockevent;
unsigned int cpu = smp_processor_id();
cd->cpumask = cpumask_of(cpu);
clockevent_set_clock(cd, MFGPT_TICK_RATE);
cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
/* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */
_wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
/* Enable Interrupt Gate 5 */
_wrmsr(DIVIL_MSR_REG(PIC_ZSEL_LOW), 0, 0x50000);
/* get MFGPT base address */
_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
clockevents_register_device(cd);
setup_irq(CS5536_MFGPT_INTR, &irq5);
}
/*
* Since the MFGPT overflows every tick, its not very useful
* to just read by itself. So use jiffies to emulate a free
* running counter:
*/
static cycle_t mfgpt_read(struct clocksource *cs)
{
unsigned long flags;
int count;
u32 jifs;
static int old_count;
static u32 old_jifs;
spin_lock_irqsave(&mfgpt_lock, flags);
/*
* Although our caller may have the read side of xtime_lock,
* this is now a seqlock, and we are cheating in this routine
* by having side effects on state that we cannot undo if
* there is a collision on the seqlock and our caller has to
* retry. (Namely, old_jifs and old_count.) So we must treat
* jiffies as volatile despite the lock. We read jiffies
* before latching the timer count to guarantee that although
* the jiffies value might be older than the count (that is,
* the counter may underflow between the last point where
* jiffies was incremented and the point where we latch the
* count), it cannot be newer.
*/
jifs = jiffies;
/* read the count */
count = inw(MFGPT0_CNT);
/*
* It's possible for count to appear to go the wrong way for this
* reason:
*
* The timer counter underflows, but we haven't handled the resulting
* interrupt and incremented jiffies yet.
*
* Previous attempts to handle these cases intelligently were buggy, so
* we just do the simple thing now.
*/
if (count < old_count && jifs == old_jifs)
count = old_count;
old_count = count;
old_jifs = jifs;
spin_unlock_irqrestore(&mfgpt_lock, flags);
return (cycle_t) (jifs * COMPARE) + count;
}
static struct clocksource clocksource_mfgpt = {
.name = "mfgpt",
.rating = 120, /* Functional for real use, but not desired */
.read = mfgpt_read,
.mask = CLOCKSOURCE_MASK(32),
};
int __init init_mfgpt_clocksource(void)
{
if (num_possible_cpus() > 1) /* MFGPT does not scale! */
return 0;
return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
}
arch_initcall(init_mfgpt_clocksource);
@@ -0,0 +1,149 @@
/*
* the OHCI Virtual Support Module of AMD CS5536
*
* Copyright (C) 2007 Lemote, Inc.
* Author : jlliu, liujl@lemote.com
*
* Copyright (C) 2009 Lemote, Inc.
* Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <cs5536/cs5536.h>
#include <cs5536/cs5536_pci.h>
void pci_ohci_write_reg(int reg, u32 value)
{
u32 hi = 0, lo = value;
switch (reg) {
case PCI_COMMAND:
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
if (value & PCI_COMMAND_MASTER)
hi |= PCI_COMMAND_MASTER;
else
hi &= ~PCI_COMMAND_MASTER;
if (value & PCI_COMMAND_MEMORY)
hi |= PCI_COMMAND_MEMORY;
else
hi &= ~PCI_COMMAND_MEMORY;
_wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
break;
case PCI_STATUS:
if (value & PCI_STATUS_PARITY) {
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG) {
lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
}
}
break;
case PCI_BAR0_REG:
if (value == PCI_BAR_RANGE_MASK) {
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
lo |= SOFT_BAR_OHCI_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else if ((value & 0x01) == 0x00) {
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
lo = value;
_wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
value &= 0xfffffff0;
hi = 0x40000000 | ((value & 0xff000000) >> 24);
lo = 0x000fffff | ((value & 0x00fff000) << 8);
_wrmsr(GLIU_MSR_REG(GLIU_P2D_BM3), hi, lo);
}
break;
case PCI_OHCI_INT_REG:
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
lo &= ~(0xf << PIC_YSEL_LOW_USB_SHIFT);
if (value) /* enable all the usb interrupt in PIC */
lo |= (CS5536_USB_INTR << PIC_YSEL_LOW_USB_SHIFT);
_wrmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), hi, lo);
break;
default:
break;
}
}
u32 pci_ohci_read_reg(int reg)
{
u32 conf_data = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
conf_data =
CFG_PCI_VENDOR_ID(CS5536_OHCI_DEVICE_ID, CS5536_VENDOR_ID);
break;
case PCI_COMMAND:
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
if (hi & PCI_COMMAND_MASTER)
conf_data |= PCI_COMMAND_MASTER;
if (hi & PCI_COMMAND_MEMORY)
conf_data |= PCI_COMMAND_MEMORY;
break;
case PCI_STATUS:
conf_data |= PCI_STATUS_66MHZ;
conf_data |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
conf_data |= PCI_STATUS_PARITY;
conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
conf_data = lo & 0x000000ff;
conf_data |= (CS5536_OHCI_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
conf_data =
CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
PCI_NORMAL_LATENCY_TIMER);
break;
case PCI_BAR0_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_OHCI_FLAG) {
conf_data = CS5536_OHCI_RANGE |
PCI_BASE_ADDRESS_SPACE_MEMORY;
lo &= ~SOFT_BAR_OHCI_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
conf_data = lo & 0xffffff00;
conf_data &= ~0x0000000f; /* 32bit mem */
}
break;
case PCI_CARDBUS_CIS:
conf_data = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_SUBSYSTEM_VENDOR_ID:
conf_data =
CFG_PCI_VENDOR_ID(CS5536_OHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
break;
case PCI_ROM_ADDRESS:
conf_data = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
conf_data = PCI_CAPLIST_USB_POINTER;
break;
case PCI_INTERRUPT_LINE:
conf_data =
CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
break;
case PCI_OHCI_INT_REG:
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
if ((lo & 0x00000f00) == CS5536_USB_INTR)
conf_data = 1;
break;
default:
break;
}
return conf_data;
}
@@ -0,0 +1,87 @@
/*
* read/write operation to the PCI config space of CS5536
*
* Copyright (C) 2007 Lemote, Inc.
* Author : jlliu, liujl@lemote.com
*
* Copyright (C) 2009 Lemote, Inc.
* Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* the Virtual Support Module(VSM) for virtulizing the PCI
* configure space are defined in cs5536_modulename.c respectively,
*
* after this virtulizing, user can access the PCI configure space
* directly as a normal multi-function PCI device which follows
* the PCI-2.2 spec.
*/
#include <linux/types.h>
#include <cs5536/cs5536_vsm.h>
enum {
CS5536_FUNC_START = -1,
CS5536_ISA_FUNC,
reserved_func,
CS5536_IDE_FUNC,
CS5536_ACC_FUNC,
CS5536_OHCI_FUNC,
CS5536_EHCI_FUNC,
CS5536_FUNC_END,
};
static const cs5536_pci_vsm_write vsm_conf_write[] = {
[CS5536_ISA_FUNC] pci_isa_write_reg,
[reserved_func] NULL,
[CS5536_IDE_FUNC] pci_ide_write_reg,
[CS5536_ACC_FUNC] pci_acc_write_reg,
[CS5536_OHCI_FUNC] pci_ohci_write_reg,
[CS5536_EHCI_FUNC] pci_ehci_write_reg,
};
static const cs5536_pci_vsm_read vsm_conf_read[] = {
[CS5536_ISA_FUNC] pci_isa_read_reg,
[reserved_func] NULL,
[CS5536_IDE_FUNC] pci_ide_read_reg,
[CS5536_ACC_FUNC] pci_acc_read_reg,
[CS5536_OHCI_FUNC] pci_ohci_read_reg,
[CS5536_EHCI_FUNC] pci_ehci_read_reg,
};
/*
* write to PCI config space and transfer it to MSR write.
*/
void cs5536_pci_conf_write4(int function, int reg, u32 value)
{
if ((function <= CS5536_FUNC_START) || (function >= CS5536_FUNC_END))
return;
if ((reg < 0) || (reg > 0x100) || ((reg & 0x03) != 0))
return;
if (vsm_conf_write[function] != NULL)
vsm_conf_write[function](reg, value);
}
/*
* read PCI config space and transfer it to MSR access.
*/
u32 cs5536_pci_conf_read4(int function, int reg)
{
u32 data = 0;
if ((function <= CS5536_FUNC_START) || (function >= CS5536_FUNC_END))
return 0;
if ((reg < 0) || ((reg & 0x03) != 0))
return 0;
if (reg > 0x100)
return 0xffffffff;
if (vsm_conf_read[function] != NULL)
data = vsm_conf_read[function](reg);
return data;
}