diff mbox series

[5/6] MIPS: Loongson: Add PCI support for 7A1000

Message ID 1583742206-29163-6-git-send-email-yangtiezhu@loongson.cn
State New
Headers show
Series Add basic support for Loongson 7A1000 bridge chip | expand

Commit Message

Tiezhu Yang March 9, 2020, 8:23 a.m. UTC
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

Comments

Jiaxun Yang March 9, 2020, 8:47 a.m. UTC | #1
---- 在 星期一, 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
 > 
 >
Tiezhu Yang March 10, 2020, 3:03 a.m. UTC | #2
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 mbox series

Patch

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
+};