Message ID | 1583742206-29163-6-git-send-email-yangtiezhu@loongson.cn (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Add basic support for Loongson 7A1000 bridge chip | expand |
---- 在 星期一, 2020-03-09 16:23:25 Tiezhu Yang <yangtiezhu@loongson.cn> 撰写 ---- > Add PCI support for 7A1000 to detect PCI device. > > Co-developed-by: Jianmin Lv <lvjianmin@loongson.cn> > Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn> > Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> > --- > arch/mips/include/asm/mach-loongson64/pci.h | 1 + > arch/mips/loongson64/pci.c | 12 ++- > arch/mips/pci/Makefile | 2 +- > arch/mips/pci/ops-loongson3-ls7a.c | 132 ++++++++++++++++++++++++++++ > 4 files changed, 143 insertions(+), 4 deletions(-) > create mode 100644 arch/mips/pci/ops-loongson3-ls7a.c > > diff --git a/arch/mips/include/asm/mach-loongson64/pci.h b/arch/mips/include/asm/mach-loongson64/pci.h > index 8b59d64..42c9744 100644 > --- a/arch/mips/include/asm/mach-loongson64/pci.h > +++ b/arch/mips/include/asm/mach-loongson64/pci.h > @@ -8,6 +8,7 @@ > #define __ASM_MACH_LOONGSON64_PCI_H_ > > extern struct pci_ops loongson_pci_ops; > +extern struct pci_ops loongson_ls7a_pci_ops; > > /* this is an offset from mips_io_port_base */ > #define LOONGSON_PCI_IO_START 0x00004000UL > diff --git a/arch/mips/loongson64/pci.c b/arch/mips/loongson64/pci.c > index e84ae20..b79368f 100644 > --- a/arch/mips/loongson64/pci.c > +++ b/arch/mips/loongson64/pci.c > @@ -23,8 +23,8 @@ static struct resource loongson_pci_io_resource = { > .flags = IORESOURCE_IO, > }; > > -static struct pci_controller loongson_pci_controller = { > - .pci_ops = &loongson_pci_ops, > +static struct pci_controller loongson_pci_controller = { > + .pci_ops = NULL, > .io_resource = &loongson_pci_io_resource, > .mem_resource = &loongson_pci_mem_resource, > .mem_offset = 0x00000000UL, > @@ -36,6 +36,11 @@ extern int sbx00_acpi_init(void); > > static int __init pcibios_init(void) > { > + if (strstr(eboard->name, "780E")) > + loongson_pci_controller.pci_ops = &loongson_pci_ops; > + > + if (strstr(eboard->name, "7A1000")) > + loongson_pci_controller.pci_ops = &loongson_ls7a_pci_ops; Please do not check PCH type everywhere. > > loongson_pci_controller.io_map_base = mips_io_port_base; > loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr; > @@ -43,7 +48,8 @@ static int __init pcibios_init(void) > > register_pci_controller(&loongson_pci_controller); > > - sbx00_acpi_init(); > + if (strstr(eboard->name, "780E")) > + sbx00_acpi_init(); > > return 0; > } > diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile > index 342ce10..7256bb1 100644 > --- a/arch/mips/pci/Makefile > +++ b/arch/mips/pci/Makefile > @@ -35,7 +35,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o > obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o > obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o > obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o > -obj-$(CONFIG_MACH_LOONGSON64) += fixup-loongson3.o ops-loongson3.o > +obj-$(CONFIG_MACH_LOONGSON64) += fixup-loongson3.o ops-loongson3.o ops-loongson3-ls7a.o > obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o > obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o > obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o > diff --git a/arch/mips/pci/ops-loongson3-ls7a.c b/arch/mips/pci/ops-loongson3-ls7a.c > new file mode 100644 > index 0000000..4ed6c40 > --- /dev/null > +++ b/arch/mips/pci/ops-loongson3-ls7a.c > @@ -0,0 +1,132 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2020 Loongson Technology Corporation Limited > + * > + * Author: Jianmin Lv <lvjianmin@loongson.cn> > + * Author: Tiezhu Yang <yangtiezhu@loongson.cn> > + */ > + > +#include <linux/types.h> > +#include <linux/pci.h> > +#include <linux/kernel.h> > + > +#include <asm/mips-boards/bonito64.h> Why we need this? > + > +#include <loongson.h> > + > +#define PCI_ACCESS_READ 0 > +#define PCI_ACCESS_WRITE 1 > + > +#define HT1LO_PCICFG_BASE 0x1a000000 > +#define HT1LO_PCICFG_BASE_TP1 0x1b000000 > + > +#define HT1LO_PCICFG_BASE_EXT 0xefe00000000 > +#define HT1LO_PCICFG_BASE_TP1_EXT 0xefe10000000 > + > +static int ls7a_pci_config_access(unsigned char access_type, > + struct pci_bus *bus, unsigned int devfn, > + int where, u32 *data) > +{ > + u_int64_t addr; > + void *addrp; > + unsigned char busnum = bus->number; > + int device = PCI_SLOT(devfn); > + int function = PCI_FUNC(devfn); > + int reg = where & ~3; > + > + if (where >= PCI_CFG_SPACE_EXP_SIZE) > + return PCIBIOS_DEVICE_NOT_FOUND; > + > + if (busnum == 0 && device > 23) > + return PCIBIOS_DEVICE_NOT_FOUND; > + > + if (where < PCI_CFG_SPACE_SIZE) { /* standard config */ > + addr = (busnum << 16) | (device << 11) | (function << 8) | reg; > + if (busnum == 0) { > + addr = HT1LO_PCICFG_BASE | addr; > + addrp = (void *)TO_UNCAC(addr); > + } else { > + addr = HT1LO_PCICFG_BASE_TP1 | addr; > + addrp = (void *)TO_UNCAC(addr); > + } > + } else { /* extended config */ > + reg = (reg & 0xff) | ((reg & 0xf00) << 16); > + addr = (busnum << 16) | (device << 11) | (function << 8) | reg; > + if (busnum == 0) { > + addr = HT1LO_PCICFG_BASE_EXT | addr; > + addrp = (void *)TO_UNCAC(addr); > + } else { > + addr = HT1LO_PCICFG_BASE_TP1_EXT | addr; > + addrp = (void *)TO_UNCAC(addr); > + } > + } > + > + if (access_type == PCI_ACCESS_WRITE) > + *(unsigned int *)addrp = cpu_to_le32(*data); > + else { > + *data = le32_to_cpu(*(unsigned int *)addrp); > + if (busnum == 0 && > + reg == PCI_CLASS_REVISION && *data == 0x06000001) > + *data = (PCI_CLASS_BRIDGE_PCI << 16) | (*data & 0xffff); It should be a part of quirk. Not a part of accessing. > + > + if (*data == 0xffffffff) { > + *data = -1; > + return PCIBIOS_DEVICE_NOT_FOUND; > + } > + } > + > + return PCIBIOS_SUCCESSFUL; > +} > + > +static int ls7a_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn, > + int where, int size, u32 *val) > +{ > + int ret; > + u32 data = 0; > + > + ret = ls7a_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data); > + if (ret != PCIBIOS_SUCCESSFUL) > + return ret; > + > + if (size == 1) > + *val = (data >> ((where & 3) << 3)) & 0xff; > + else if (size == 2) > + *val = (data >> ((where & 3) << 3)) & 0xffff; > + else > + *val = data; That loggic seems identical with RS780E one, can we reuse them? > + > + return PCIBIOS_SUCCESSFUL; > +} > + > +static int ls7a_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn, > + int where, int size, u32 val) > +{ > + int ret; > + u32 data = 0; > + > + if (size == 4) > + data = val; > + else { > + ret = ls7a_pci_config_access(PCI_ACCESS_READ, bus, > + devfn, where, &data); > + if (ret != PCIBIOS_SUCCESSFUL) > + return ret; > + > + if (size == 1) > + data = (data & ~(0xff << ((where & 3) << 3))) | > + (val << ((where & 3) << 3)); > + else if (size == 2) > + data = (data & ~(0xffff << ((where & 3) << 3))) | > + (val << ((where & 3) << 3)); > + } > + > + ret = ls7a_pci_config_access(PCI_ACCESS_WRITE, bus, > + devfn, where, &data); > + > + return ret; > +} > + > +struct pci_ops loongson_ls7a_pci_ops = { > + .read = ls7a_pci_pcibios_read, > + .write = ls7a_pci_pcibios_write > +}; > -- > 2.1.0 > >
On 03/09/2020 04:47 PM, Jiaxun Yang wrote: > > ---- 在 星期一, 2020-03-09 16:23:25 Tiezhu Yang <yangtiezhu@loongson.cn> 撰写 ---- > > Add PCI support for 7A1000 to detect PCI device. > > > > Co-developed-by: Jianmin Lv <lvjianmin@loongson.cn> > > Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn> > > Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> > > --- > > arch/mips/include/asm/mach-loongson64/pci.h | 1 + > > arch/mips/loongson64/pci.c | 12 ++- > > arch/mips/pci/Makefile | 2 +- > > arch/mips/pci/ops-loongson3-ls7a.c | 132 ++++++++++++++++++++++++++++ > > 4 files changed, 143 insertions(+), 4 deletions(-) > > create mode 100644 arch/mips/pci/ops-loongson3-ls7a.c > > > > diff --git a/arch/mips/include/asm/mach-loongson64/pci.h b/arch/mips/include/asm/mach-loongson64/pci.h > > index 8b59d64..42c9744 100644 > > --- a/arch/mips/include/asm/mach-loongson64/pci.h > > +++ b/arch/mips/include/asm/mach-loongson64/pci.h > > @@ -8,6 +8,7 @@ > > #define __ASM_MACH_LOONGSON64_PCI_H_ > > > > extern struct pci_ops loongson_pci_ops; > > +extern struct pci_ops loongson_ls7a_pci_ops; > > > > /* this is an offset from mips_io_port_base */ > > #define LOONGSON_PCI_IO_START 0x00004000UL > > diff --git a/arch/mips/loongson64/pci.c b/arch/mips/loongson64/pci.c > > index e84ae20..b79368f 100644 > > --- a/arch/mips/loongson64/pci.c > > +++ b/arch/mips/loongson64/pci.c > > @@ -23,8 +23,8 @@ static struct resource loongson_pci_io_resource = { > > .flags = IORESOURCE_IO, > > }; > > > > -static struct pci_controller loongson_pci_controller = { > > - .pci_ops = &loongson_pci_ops, > > +static struct pci_controller loongson_pci_controller = { > > + .pci_ops = NULL, > > .io_resource = &loongson_pci_io_resource, > > .mem_resource = &loongson_pci_mem_resource, > > .mem_offset = 0x00000000UL, > > @@ -36,6 +36,11 @@ extern int sbx00_acpi_init(void); > > > > static int __init pcibios_init(void) > > { > > + if (strstr(eboard->name, "780E")) > > + loongson_pci_controller.pci_ops = &loongson_pci_ops; > > + > > + if (strstr(eboard->name, "7A1000")) > > + loongson_pci_controller.pci_ops = &loongson_ls7a_pci_ops; > > Please do not check PCH type everywhere. Yes, you are right. > > > > > loongson_pci_controller.io_map_base = mips_io_port_base; > > loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr; > > @@ -43,7 +48,8 @@ static int __init pcibios_init(void) > > > > register_pci_controller(&loongson_pci_controller); > > > > - sbx00_acpi_init(); > > + if (strstr(eboard->name, "780E")) > > + sbx00_acpi_init(); > > > > return 0; > > } > > diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile > > index 342ce10..7256bb1 100644 > > --- a/arch/mips/pci/Makefile > > +++ b/arch/mips/pci/Makefile > > @@ -35,7 +35,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o > > obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o > > obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o > > obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o > > -obj-$(CONFIG_MACH_LOONGSON64) += fixup-loongson3.o ops-loongson3.o > > +obj-$(CONFIG_MACH_LOONGSON64) += fixup-loongson3.o ops-loongson3.o ops-loongson3-ls7a.o > > obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o > > obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o > > obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o > > diff --git a/arch/mips/pci/ops-loongson3-ls7a.c b/arch/mips/pci/ops-loongson3-ls7a.c > > new file mode 100644 > > index 0000000..4ed6c40 > > --- /dev/null > > +++ b/arch/mips/pci/ops-loongson3-ls7a.c > > @@ -0,0 +1,132 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2020 Loongson Technology Corporation Limited > > + * > > + * Author: Jianmin Lv <lvjianmin@loongson.cn> > > + * Author: Tiezhu Yang <yangtiezhu@loongson.cn> > > + */ > > + > > +#include <linux/types.h> > > +#include <linux/pci.h> > > +#include <linux/kernel.h> > > + > > +#include <asm/mips-boards/bonito64.h> > > Why we need this? I will check it, if it is useless, I will remove it. > > > + > > +#include <loongson.h> > > + > > +#define PCI_ACCESS_READ 0 > > +#define PCI_ACCESS_WRITE 1 > > + > > +#define HT1LO_PCICFG_BASE 0x1a000000 > > +#define HT1LO_PCICFG_BASE_TP1 0x1b000000 > > + > > +#define HT1LO_PCICFG_BASE_EXT 0xefe00000000 > > +#define HT1LO_PCICFG_BASE_TP1_EXT 0xefe10000000 > > + > > +static int ls7a_pci_config_access(unsigned char access_type, > > + struct pci_bus *bus, unsigned int devfn, > > + int where, u32 *data) > > +{ > > + u_int64_t addr; > > + void *addrp; > > + unsigned char busnum = bus->number; > > + int device = PCI_SLOT(devfn); > > + int function = PCI_FUNC(devfn); > > + int reg = where & ~3; > > + > > + if (where >= PCI_CFG_SPACE_EXP_SIZE) > > + return PCIBIOS_DEVICE_NOT_FOUND; > > + > > + if (busnum == 0 && device > 23) > > + return PCIBIOS_DEVICE_NOT_FOUND; > > + > > + if (where < PCI_CFG_SPACE_SIZE) { /* standard config */ > > + addr = (busnum << 16) | (device << 11) | (function << 8) | reg; > > + if (busnum == 0) { > > + addr = HT1LO_PCICFG_BASE | addr; > > + addrp = (void *)TO_UNCAC(addr); > > + } else { > > + addr = HT1LO_PCICFG_BASE_TP1 | addr; > > + addrp = (void *)TO_UNCAC(addr); > > + } > > + } else { /* extended config */ > > + reg = (reg & 0xff) | ((reg & 0xf00) << 16); > > + addr = (busnum << 16) | (device << 11) | (function << 8) | reg; > > + if (busnum == 0) { > > + addr = HT1LO_PCICFG_BASE_EXT | addr; > > + addrp = (void *)TO_UNCAC(addr); > > + } else { > > + addr = HT1LO_PCICFG_BASE_TP1_EXT | addr; > > + addrp = (void *)TO_UNCAC(addr); > > + } > > + } > > + > > + if (access_type == PCI_ACCESS_WRITE) > > + *(unsigned int *)addrp = cpu_to_le32(*data); > > + else { > > + *data = le32_to_cpu(*(unsigned int *)addrp); > > + if (busnum == 0 && > > + reg == PCI_CLASS_REVISION && *data == 0x06000001) > > + *data = (PCI_CLASS_BRIDGE_PCI << 16) | (*data & 0xffff); > > It should be a part of quirk. Not a part of accessing. > > > + > > + if (*data == 0xffffffff) { > > + *data = -1; > > + return PCIBIOS_DEVICE_NOT_FOUND; > > + } > > + } > > + > > + return PCIBIOS_SUCCESSFUL; > > +} > > + > > +static int ls7a_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn, > > + int where, int size, u32 *val) > > +{ > > + int ret; > > + u32 data = 0; > > + > > + ret = ls7a_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data); > > + if (ret != PCIBIOS_SUCCESSFUL) > > + return ret; > > + > > + if (size == 1) > > + *val = (data >> ((where & 3) << 3)) & 0xff; > > + else if (size == 2) > > + *val = (data >> ((where & 3) << 3)) & 0xffff; > > + else > > + *val = data; > > That loggic seems identical with RS780E one, can we reuse them? OK, I will do it. Thanks, Tiezhu Yang > >> + > > + return PCIBIOS_SUCCESSFUL; > > +} > > + > > +static int ls7a_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn, > > + int where, int size, u32 val) > > +{ > > + int ret; > > + u32 data = 0; > > + > > + if (size == 4) > > + data = val; > > + else { > > + ret = ls7a_pci_config_access(PCI_ACCESS_READ, bus, > > + devfn, where, &data); > > + if (ret != PCIBIOS_SUCCESSFUL) > > + return ret; > > + > > + if (size == 1) > > + data = (data & ~(0xff << ((where & 3) << 3))) | > > + (val << ((where & 3) << 3)); > > + else if (size == 2) > > + data = (data & ~(0xffff << ((where & 3) << 3))) | > > + (val << ((where & 3) << 3)); > > + } > > + > > + ret = ls7a_pci_config_access(PCI_ACCESS_WRITE, bus, > > + devfn, where, &data); > > + > > + return ret; > > +} > > + > > +struct pci_ops loongson_ls7a_pci_ops = { > > + .read = ls7a_pci_pcibios_read, > > + .write = ls7a_pci_pcibios_write > > +}; > > -- > > 2.1.0 > > > >
diff --git a/arch/mips/include/asm/mach-loongson64/pci.h b/arch/mips/include/asm/mach-loongson64/pci.h index 8b59d64..42c9744 100644 --- a/arch/mips/include/asm/mach-loongson64/pci.h +++ b/arch/mips/include/asm/mach-loongson64/pci.h @@ -8,6 +8,7 @@ #define __ASM_MACH_LOONGSON64_PCI_H_ extern struct pci_ops loongson_pci_ops; +extern struct pci_ops loongson_ls7a_pci_ops; /* this is an offset from mips_io_port_base */ #define LOONGSON_PCI_IO_START 0x00004000UL diff --git a/arch/mips/loongson64/pci.c b/arch/mips/loongson64/pci.c index e84ae20..b79368f 100644 --- a/arch/mips/loongson64/pci.c +++ b/arch/mips/loongson64/pci.c @@ -23,8 +23,8 @@ static struct resource loongson_pci_io_resource = { .flags = IORESOURCE_IO, }; -static struct pci_controller loongson_pci_controller = { - .pci_ops = &loongson_pci_ops, +static struct pci_controller loongson_pci_controller = { + .pci_ops = NULL, .io_resource = &loongson_pci_io_resource, .mem_resource = &loongson_pci_mem_resource, .mem_offset = 0x00000000UL, @@ -36,6 +36,11 @@ extern int sbx00_acpi_init(void); static int __init pcibios_init(void) { + if (strstr(eboard->name, "780E")) + loongson_pci_controller.pci_ops = &loongson_pci_ops; + + if (strstr(eboard->name, "7A1000")) + loongson_pci_controller.pci_ops = &loongson_ls7a_pci_ops; loongson_pci_controller.io_map_base = mips_io_port_base; loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr; @@ -43,7 +48,8 @@ static int __init pcibios_init(void) register_pci_controller(&loongson_pci_controller); - sbx00_acpi_init(); + if (strstr(eboard->name, "780E")) + sbx00_acpi_init(); return 0; } diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 342ce10..7256bb1 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o -obj-$(CONFIG_MACH_LOONGSON64) += fixup-loongson3.o ops-loongson3.o +obj-$(CONFIG_MACH_LOONGSON64) += fixup-loongson3.o ops-loongson3.o ops-loongson3-ls7a.o obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o diff --git a/arch/mips/pci/ops-loongson3-ls7a.c b/arch/mips/pci/ops-loongson3-ls7a.c new file mode 100644 index 0000000..4ed6c40 --- /dev/null +++ b/arch/mips/pci/ops-loongson3-ls7a.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Loongson Technology Corporation Limited + * + * Author: Jianmin Lv <lvjianmin@loongson.cn> + * Author: Tiezhu Yang <yangtiezhu@loongson.cn> + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> + +#include <asm/mips-boards/bonito64.h> + +#include <loongson.h> + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +#define HT1LO_PCICFG_BASE 0x1a000000 +#define HT1LO_PCICFG_BASE_TP1 0x1b000000 + +#define HT1LO_PCICFG_BASE_EXT 0xefe00000000 +#define HT1LO_PCICFG_BASE_TP1_EXT 0xefe10000000 + +static int ls7a_pci_config_access(unsigned char access_type, + struct pci_bus *bus, unsigned int devfn, + int where, u32 *data) +{ + u_int64_t addr; + void *addrp; + unsigned char busnum = bus->number; + int device = PCI_SLOT(devfn); + int function = PCI_FUNC(devfn); + int reg = where & ~3; + + if (where >= PCI_CFG_SPACE_EXP_SIZE) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (busnum == 0 && device > 23) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (where < PCI_CFG_SPACE_SIZE) { /* standard config */ + addr = (busnum << 16) | (device << 11) | (function << 8) | reg; + if (busnum == 0) { + addr = HT1LO_PCICFG_BASE | addr; + addrp = (void *)TO_UNCAC(addr); + } else { + addr = HT1LO_PCICFG_BASE_TP1 | addr; + addrp = (void *)TO_UNCAC(addr); + } + } else { /* extended config */ + reg = (reg & 0xff) | ((reg & 0xf00) << 16); + addr = (busnum << 16) | (device << 11) | (function << 8) | reg; + if (busnum == 0) { + addr = HT1LO_PCICFG_BASE_EXT | addr; + addrp = (void *)TO_UNCAC(addr); + } else { + addr = HT1LO_PCICFG_BASE_TP1_EXT | addr; + addrp = (void *)TO_UNCAC(addr); + } + } + + if (access_type == PCI_ACCESS_WRITE) + *(unsigned int *)addrp = cpu_to_le32(*data); + else { + *data = le32_to_cpu(*(unsigned int *)addrp); + if (busnum == 0 && + reg == PCI_CLASS_REVISION && *data == 0x06000001) + *data = (PCI_CLASS_BRIDGE_PCI << 16) | (*data & 0xffff); + + if (*data == 0xffffffff) { + *data = -1; + return PCIBIOS_DEVICE_NOT_FOUND; + } + } + + return PCIBIOS_SUCCESSFUL; +} + +static int ls7a_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + int ret; + u32 data = 0; + + ret = ls7a_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data); + if (ret != PCIBIOS_SUCCESSFUL) + return ret; + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 3) << 3)) & 0xffff; + else + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + +static int ls7a_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + int ret; + u32 data = 0; + + if (size == 4) + data = val; + else { + ret = ls7a_pci_config_access(PCI_ACCESS_READ, bus, + devfn, where, &data); + if (ret != PCIBIOS_SUCCESSFUL) + return ret; + + if (size == 1) + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else if (size == 2) + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + } + + ret = ls7a_pci_config_access(PCI_ACCESS_WRITE, bus, + devfn, where, &data); + + return ret; +} + +struct pci_ops loongson_ls7a_pci_ops = { + .read = ls7a_pci_pcibios_read, + .write = ls7a_pci_pcibios_write +};