diff options
author | Visa Hankala <visa@cvs.openbsd.org> | 2016-11-17 14:41:22 +0000 |
---|---|---|
committer | Visa Hankala <visa@cvs.openbsd.org> | 2016-11-17 14:41:22 +0000 |
commit | 57e5d4c118b16705a380446009d65f0b39f9a495 (patch) | |
tree | e5a40fda2477afbd78a714099714b45308399bac /sys | |
parent | 47227fa5812f4aa501f90b47a9ae06b1f67c2504 (diff) |
Add drivers for PCI host bridge and built-in UARTs on Loongson 3A,
and put the pieces together by platform glue.
Feedback from miod@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/loongson/conf/files.loongson | 17 | ||||
-rw-r--r-- | sys/arch/loongson/dev/com_leioc.c | 106 | ||||
-rw-r--r-- | sys/arch/loongson/dev/htb.c | 434 | ||||
-rw-r--r-- | sys/arch/loongson/dev/htbreg.h | 38 | ||||
-rw-r--r-- | sys/arch/loongson/dev/htbvar.h | 28 | ||||
-rw-r--r-- | sys/arch/loongson/dev/leioc.c | 82 | ||||
-rw-r--r-- | sys/arch/loongson/dev/leiocreg.h | 37 | ||||
-rw-r--r-- | sys/arch/loongson/dev/leiocvar.h | 34 | ||||
-rw-r--r-- | sys/arch/loongson/dev/mainbus.c | 8 | ||||
-rw-r--r-- | sys/arch/loongson/include/intr.h | 5 | ||||
-rw-r--r-- | sys/arch/loongson/loongson/generic3a_machdep.c | 281 | ||||
-rw-r--r-- | sys/arch/loongson/loongson/machdep.c | 33 |
12 files changed, 1091 insertions, 12 deletions
diff --git a/sys/arch/loongson/conf/files.loongson b/sys/arch/loongson/conf/files.loongson index 52d579e36f6..f647efbd38c 100644 --- a/sys/arch/loongson/conf/files.loongson +++ b/sys/arch/loongson/conf/files.loongson @@ -1,4 +1,4 @@ -# $OpenBSD: files.loongson,v 1.23 2016/11/06 10:20:33 visa Exp $ +# $OpenBSD: files.loongson,v 1.24 2016/11/17 14:41:21 visa Exp $ # Standard stanzas config(8) can't run without maxpartitions 16 @@ -19,8 +19,8 @@ file arch/loongson/loongson/conf.c file arch/loongson/loongson/disksubr.c disk file arch/loongson/loongson/gdium_machdep.c cpu_loongson2 file arch/loongson/loongson/generic2e_machdep.c cpu_loongson2 +file arch/loongson/loongson/generic3a_machdep.c cpu_loongson3 file arch/loongson/loongson/isa_machdep.c isa -file arch/loongson/loongson/lemote3a_machdep.c cpu_loongson3 file arch/loongson/loongson/loongson2_machdep.c file arch/loongson/loongson/loongson3_intr.c cpu_loongson3 file arch/loongson/loongson/loongson3_machdep.c cpu_loongson3 @@ -63,6 +63,10 @@ device bonito {}: pcibus attach bonito at mainbus file arch/loongson/dev/bonito.c bonito +device htb {}: pcibus +attach htb at mainbus +file arch/loongson/dev/htb.c htb + # AMD Geode CS5536 companion chip file arch/loongson/dev/glx.c bonito & pci @@ -129,3 +133,12 @@ file arch/loongson/dev/apm.c apm needs-flag device glxclk attach glxclk at glxpcib file arch/loongson/dev/glxclk.c glxclk + +define leiobus {} + +device leioc: leiobus +attach leioc at mainbus +file arch/loongson/dev/leioc.c leioc + +attach com at leiobus with com_leioc +file arch/loongson/dev/com_leioc.c com_leioc diff --git a/sys/arch/loongson/dev/com_leioc.c b/sys/arch/loongson/dev/com_leioc.c new file mode 100644 index 00000000000..2c4399cee1a --- /dev/null +++ b/sys/arch/loongson/dev/com_leioc.c @@ -0,0 +1,106 @@ +/* $OpenBSD: com_leioc.c,v 1.1 2016/11/17 14:41:21 visa Exp $ */ + +/* + * Copyright (c) 2016 Visa Hankala + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/termios.h> +#include <sys/tty.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/loongson3.h> + +#include <dev/ic/comreg.h> +#include <dev/ic/comvar.h> + +#include <loongson/dev/leiocreg.h> +#include <loongson/dev/leiocvar.h> + +#define UART_FREQ 33000000 +#define UART_RATE 115200 + +int com_leioc_match(struct device *, void *, void *); +void com_leioc_attach(struct device *, struct device *, void *); + +const struct cfattach com_leioc_ca = { + sizeof(struct com_softc), com_leioc_match, com_leioc_attach +}; + +extern struct cfdriver com_cd; + +int +com_leioc_match(struct device *parent, void *match, void *aux) +{ + struct leioc_attach_args *laa = aux; + + if (strcmp(laa->laa_name, com_cd.cd_name) == 0) + return 1; + + return 0; +} + +void +com_leioc_attach(struct device *parent, struct device *self, void *aux) +{ + struct leioc_attach_args *laa = aux; + struct com_softc *sc = (void *)self; + int console = 0; + + if (comconsiot == &leioc_io_space_tag && comconsaddr == laa->laa_base) + console = 1; + + sc->sc_hwflags = 0; + sc->sc_swflags = 0; + sc->sc_frequency = UART_FREQ; + + if (!console || comconsattached) { + sc->sc_iot = &leioc_io_space_tag; + sc->sc_iobase = laa->laa_base; + if (bus_space_map(sc->sc_iot, sc->sc_iobase, COM_NPORTS, 0, + &sc->sc_ioh)) { + printf(": could not map UART registers\n"); + return; + } + } else { + /* Reuse the early console settings. */ + sc->sc_iot = comconsiot; + sc->sc_iobase = comconsaddr; + if (comcnattach(sc->sc_iot, sc->sc_iobase, comconsrate, + sc->sc_frequency, comconscflag)) + panic("could not set up serial console"); + sc->sc_ioh = comconsioh; + } + + com_attach_subr(sc); + + loongson3_intr_establish(LS3_IRQ_LPC, IPL_TTY, comintr, sc, + sc->sc_dev.dv_xname); +} + +void +leioc_cons_setup(void) +{ + comconsiot = &leioc_io_space_tag; + comconsaddr = LEIOC_UART0_BASE; + comconsfreq = UART_FREQ; + comconsrate = UART_RATE; + comconscflag = (TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | + CS8 | CLOCAL; +} diff --git a/sys/arch/loongson/dev/htb.c b/sys/arch/loongson/dev/htb.c new file mode 100644 index 00000000000..2dd3057bee5 --- /dev/null +++ b/sys/arch/loongson/dev/htb.c @@ -0,0 +1,434 @@ +/* $OpenBSD: htb.c,v 1.1 2016/11/17 14:41:21 visa Exp $ */ + +/* + * Copyright (c) 2016 Visa Hankala + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * PCI host bridge driver for Loongson 3A. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/loongson3.h> + +#include <dev/pci/pcidevs.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/ppbreg.h> + +#include <loongson/dev/htbreg.h> +#include <loongson/dev/htbvar.h> + +struct htb_softc { + struct device sc_dev; + struct mips_pci_chipset sc_pc; +}; + +int htb_match(struct device *, void *, void *); +void htb_attach(struct device *, struct device *, void *); +int htb_print(void *, const char *); + +void htb_attach_hook(struct device *, struct device *, + struct pcibus_attach_args *pba); +int htb_bus_maxdevs(void *, int); +pcitag_t htb_make_tag(void *, int, int, int); +void htb_decompose_tag(void *, pcitag_t, int *, int *, int *); +int htb_conf_addr(const struct bonito_config *, pcitag_t, int, + u_int32_t *, u_int32_t *); +int htb_conf_size(void *, pcitag_t); +pcireg_t htb_conf_read(void *, pcitag_t, int); +void htb_conf_write(void *, pcitag_t, int, pcireg_t); +int htb_pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *); +const char * + htb_pci_intr_string(void *, pci_intr_handle_t); +void *htb_pci_intr_establish(void *, pci_intr_handle_t, int, + int (*)(void *), void *, char *); +void htb_pci_intr_disestablish(void *, void *); + +bus_addr_t htb_pa_to_device(paddr_t); +paddr_t htb_device_to_pa(bus_addr_t); + +int htb_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +int htb_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +paddr_t htb_mem_mmap(bus_space_tag_t, bus_addr_t, off_t, int, int); + +paddr_t htb_cfg_space_addr(pcitag_t, int); + +pcireg_t htb_conf_read_early(pcitag_t, int); +pcitag_t htb_make_tag_early(int, int, int); + +const struct cfattach htb_ca = { + sizeof(struct htb_softc), htb_match, htb_attach +}; + +struct cfdriver htb_cd = { + NULL, "htb", DV_DULL +}; + +struct machine_bus_dma_tag htb_bus_dma_tag = { + ._dmamap_create = _dmamap_create, + ._dmamap_destroy = _dmamap_destroy, + ._dmamap_load = _dmamap_load, + ._dmamap_load_mbuf = _dmamap_load_mbuf, + ._dmamap_load_uio = _dmamap_load_uio, + ._dmamap_load_raw = _dmamap_load_raw, + ._dmamap_load_buffer = _dmamap_load_buffer, + ._dmamap_unload = _dmamap_unload, + ._dmamap_sync = _dmamap_sync, + ._dmamem_alloc = _dmamem_alloc, + ._dmamem_free = _dmamem_free, + ._dmamem_map = _dmamem_map, + ._dmamem_unmap = _dmamem_unmap, + ._dmamem_mmap = _dmamem_mmap, + + ._pa_to_device = htb_pa_to_device, + ._device_to_pa = htb_device_to_pa +}; + +struct mips_bus_space htb_pci_io_space_tag = { + .bus_base = PHYS_TO_XKPHYS(HTB_IO_BASE, CCA_NC), + ._space_read_1 = generic_space_read_1, + ._space_write_1 = generic_space_write_1, + ._space_read_2 = generic_space_read_2, + ._space_write_2 = generic_space_write_2, + ._space_read_4 = generic_space_read_4, + ._space_write_4 = generic_space_write_4, + ._space_read_8 = generic_space_read_8, + ._space_write_8 = generic_space_write_8, + ._space_read_raw_2 = generic_space_read_raw_2, + ._space_write_raw_2 = generic_space_write_raw_2, + ._space_read_raw_4 = generic_space_read_raw_4, + ._space_write_raw_4 = generic_space_write_raw_4, + ._space_read_raw_8 = generic_space_read_raw_8, + ._space_write_raw_8 = generic_space_write_raw_8, + ._space_map = htb_io_map, + ._space_unmap = generic_space_unmap, + ._space_subregion = generic_space_region, + ._space_vaddr = generic_space_vaddr, + ._space_mmap = generic_space_mmap +}; + +struct mips_bus_space htb_pci_mem_space_tag = { + .bus_base = PHYS_TO_XKPHYS(0, CCA_NC), + ._space_read_1 = generic_space_read_1, + ._space_write_1 = generic_space_write_1, + ._space_read_2 = generic_space_read_2, + ._space_write_2 = generic_space_write_2, + ._space_read_4 = generic_space_read_4, + ._space_write_4 = generic_space_write_4, + ._space_read_8 = generic_space_read_8, + ._space_write_8 = generic_space_write_8, + ._space_read_raw_2 = generic_space_read_raw_2, + ._space_write_raw_2 = generic_space_write_raw_2, + ._space_read_raw_4 = generic_space_read_raw_4, + ._space_write_raw_4 = generic_space_write_raw_4, + ._space_read_raw_8 = generic_space_read_raw_8, + ._space_write_raw_8 = generic_space_write_raw_8, + ._space_map = htb_mem_map, + ._space_unmap = generic_space_unmap, + ._space_subregion = generic_space_region, + ._space_vaddr = generic_space_vaddr, + ._space_mmap = htb_mem_mmap +}; + +int +htb_match(struct device *parent, void *match, void *aux) +{ + struct mainbus_attach_args *maa = aux; + + if (loongson_ver != 0x3a && loongson_ver != 0x3b) + return 0; + + if (strcmp(maa->maa_name, htb_cd.cd_name) != 0) + return 0; + + return 1; +} + +void +htb_attach(struct device *parent, struct device *self, void *aux) +{ + struct pcibus_attach_args pba; + struct htb_softc *sc = (struct htb_softc *)self; + pci_chipset_tag_t pc = &sc->sc_pc; + + printf("\n"); + + pc->pc_conf_v = sc; + pc->pc_attach_hook = htb_attach_hook; + pc->pc_bus_maxdevs = htb_bus_maxdevs; + pc->pc_make_tag = htb_make_tag; + pc->pc_decompose_tag = htb_decompose_tag; + pc->pc_conf_size = htb_conf_size; + pc->pc_conf_read = htb_conf_read; + pc->pc_conf_write = htb_conf_write; + + pc->pc_intr_v = sc; + pc->pc_intr_map = htb_pci_intr_map; + pc->pc_intr_string = htb_pci_intr_string; + pc->pc_intr_establish = htb_pci_intr_establish; + pc->pc_intr_disestablish = htb_pci_intr_disestablish; + + memset(&pba, 0, sizeof(pba)); + pba.pba_busname = "pci"; + pba.pba_iot = &htb_pci_io_space_tag; + pba.pba_memt = &htb_pci_mem_space_tag; + pba.pba_dmat = &htb_bus_dma_tag; + pba.pba_pc = pc; + pba.pba_ioex = extent_create("htb_io", 0, 0xffffffff, M_DEVBUF, + NULL, 0, EX_NOWAIT | EX_FILLED); + if (pba.pba_ioex != NULL) { + extent_free(pba.pba_ioex, 0, HTB_IO_SIZE, EX_NOWAIT); + } + pba.pba_memex = extent_create("htb_mem", 0, 0xffffffff, M_DEVBUF, + NULL, 0, EX_NOWAIT | EX_FILLED); + if (pba.pba_memex != NULL) { + extent_free(pba.pba_memex, HTB_MEM_BASE, HTB_MEM_SIZE, + EX_NOWAIT); + } + pba.pba_domain = pci_ndomains++; + pba.pba_bus = 0; + config_found(&sc->sc_dev, &pba, htb_print); +} + +int +htb_print(void *aux, const char *pnp) +{ + struct pcibus_attach_args *pba = aux; + + if (pnp) + printf("%s at %s", pba->pba_busname, pnp); + printf(" bus %d", pba->pba_bus); + + return UNCONF; +} + +void +htb_attach_hook(struct device *parent, struct device *self, + struct pcibus_attach_args *pba) +{ +} + +int +htb_bus_maxdevs(void *v, int busno) +{ + return 32; +} + +pcitag_t +htb_make_tag(void *unused, int b, int d, int f) +{ + return (b << 16) | (d << 11) | (f << 8); +} + +void +htb_decompose_tag(void *unused, pcitag_t tag, int *bp, int *dp, int *fp) +{ + if (bp != NULL) + *bp = (tag >> 16) & 0xff; + if (dp != NULL) + *dp = (tag >> 11) & 0x1f; + if (fp != NULL) + *fp = (tag >> 8) & 0x7; +} + +int +htb_conf_addr(const struct bonito_config *bc, pcitag_t tag, int offset, + u_int32_t *cfgoff, u_int32_t *pcimap_cfg) +{ + return -1; +} + +int +htb_conf_size(void *v, pcitag_t tag) +{ + return PCIE_CONFIG_SPACE_SIZE; +} + +pcireg_t +htb_conf_read(void *v, pcitag_t tag, int offset) +{ + return REGVAL(htb_cfg_space_addr(tag, offset)); +} + +void +htb_conf_write(void *v, pcitag_t tag, int offset, pcireg_t data) +{ + REGVAL(htb_cfg_space_addr(tag, offset)) = data; +} + +paddr_t +htb_cfg_space_addr(pcitag_t tag, int offset) +{ + paddr_t pa; + int bus; + + htb_decompose_tag(NULL, tag, &bus, NULL, NULL); + if (bus == 0) + pa = HTB_CFG_TYPE0_BASE; + else + pa = HTB_CFG_TYPE1_BASE; + return pa + tag + (offset & 0xfffc); +} + +/* + * PCI interrupt handling + */ + +int +htb_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) +{ + int dev, pin; + + *ihp = (pci_intr_handle_t)-1; + + if (pa->pa_intrpin == 0) + return 1; + + if (pa->pa_intrpin > PCI_INTERRUPT_PIN_MAX) { + printf(": bad interrupt pin %d\n", pa->pa_intrpin); + return 1; + } + + pci_decompose_tag(pa->pa_pc, pa->pa_tag, NULL, &dev, NULL); + if (pa->pa_bridgetag != NULL) { + pin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, dev); + if (pa->pa_bridgeih[pin - 1] != (pci_intr_handle_t)-1) { + *ihp = pa->pa_bridgeih[pin - 1]; + return 0; + } + } + + if (pa->pa_intrline != 0) { + *ihp = pa->pa_intrline; + return 0; + } + + return 1; +} + +const char * +htb_pci_intr_string(void *cookie, pci_intr_handle_t ih) +{ + static char irqstr[16]; + + snprintf(irqstr, sizeof(irqstr), "irq %lu", ih); + return irqstr; +} + +void * +htb_pci_intr_establish(void *cookie, pci_intr_handle_t ih, int level, + int (*cb)(void *), void *cbarg, char *name) +{ + return loongson3_ht_intr_establish(ih, level, cb, cbarg, name); +} + +void +htb_pci_intr_disestablish(void *cookie, void *ihp) +{ + loongson3_ht_intr_disestablish(ihp); +} + +bus_addr_t +htb_pa_to_device(paddr_t pa) +{ + return pa ^ loongson_dma_base; +} + +paddr_t +htb_device_to_pa(bus_addr_t addr) +{ + return addr ^ loongson_dma_base; +} + +/* + * bus_space(9) mapping routines + */ + +int +htb_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + const struct legacy_io_range *r; + bus_addr_t end; + + if (offs >= HTB_IO_SIZE) + return EINVAL; + + if (offs < HTB_IO_LEGACY) { + end = offs + size - 1; + if ((r = sys_platform->legacy_io_ranges) == NULL) + return ENXIO; + for ( ; r->start != 0; r++) { + if (offs >= r->start && end <= r->end) + break; + } + if (r->end == 0) + return ENXIO; + } + + *bshp = t->bus_base + offs; + return 0; +} + +int +htb_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + if (offs < HTB_MEM_BASE || offs >= HTB_MEM_BASE + HTB_MEM_SIZE) + return EINVAL; + + *bshp = t->bus_base + offs; + return 0; +} + +paddr_t +htb_mem_mmap(bus_space_tag_t t, bus_addr_t addr, off_t off, int prot, + int flags) +{ + return addr + off; +} + +/* + * Functions for system setup + */ + +void +htb_early_setup(void) +{ + pci_make_tag_early = htb_make_tag_early; + pci_conf_read_early = htb_conf_read_early; + + early_mem_t = &htb_pci_mem_space_tag; + early_io_t = &htb_pci_io_space_tag; +} + +pcitag_t +htb_make_tag_early(int b, int d, int f) +{ + return htb_make_tag(NULL, b, d, f); +} + +pcireg_t +htb_conf_read_early(pcitag_t tag, int reg) +{ + return htb_conf_read(NULL, tag, reg); +} diff --git a/sys/arch/loongson/dev/htbreg.h b/sys/arch/loongson/dev/htbreg.h new file mode 100644 index 00000000000..0480f831e51 --- /dev/null +++ b/sys/arch/loongson/dev/htbreg.h @@ -0,0 +1,38 @@ +/* $OpenBSD: htbreg.h,v 1.1 2016/11/17 14:41:21 visa Exp $ */ + +/* + * Copyright (c) 2016 Visa Hankala + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LOONGSON_DEV_HTBREG_H_ +#define _LOONGSON_DEV_HTBREG_H_ + +/* + * These addresses are translated by the CPU nodes' crossbar to the address + * space of the HT interface that connects to the northbridge. The translation + * is set up by the firmware. + */ + +#define HTB_IO_BASE 0x18000000u +#define HTB_CFG_TYPE0_BASE 0x1a000000u +#define HTB_CFG_TYPE1_BASE 0x1b000000u +#define HTB_MEM_BASE 0x40000000u + +#define HTB_IO_SIZE 0x01000000u +#define HTB_MEM_SIZE 0x40000000u + +#define HTB_IO_LEGACY 0x4000u + +#endif /* _LOONGSON_DEV_HTBREG_H_ */ diff --git a/sys/arch/loongson/dev/htbvar.h b/sys/arch/loongson/dev/htbvar.h new file mode 100644 index 00000000000..3caffe43cc3 --- /dev/null +++ b/sys/arch/loongson/dev/htbvar.h @@ -0,0 +1,28 @@ +/* $OpenBSD: htbvar.h,v 1.1 2016/11/17 14:41:21 visa Exp $ */ + +/* + * Copyright (c) 2016 Visa Hankala + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LOONGSON_DEV_HTBVAR_H_ +#define _LOONGSON_DEV_HTBVAR_H_ + +extern struct mips_isa_chipset htb_isa_chipset; +extern struct mips_bus_space htb_pci_mem_space_tag; +extern struct mips_bus_space htb_pci_io_space_tag; + +void htb_early_setup(void); + +#endif /* _LOONGSON_DEV_HTBVAR_H_ */ diff --git a/sys/arch/loongson/dev/leioc.c b/sys/arch/loongson/dev/leioc.c new file mode 100644 index 00000000000..71500f63218 --- /dev/null +++ b/sys/arch/loongson/dev/leioc.c @@ -0,0 +1,82 @@ +/* $OpenBSD: leioc.c,v 1.1 2016/11/17 14:41:21 visa Exp $ */ + +/* + * Copyright (c) 2016 Visa Hankala + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Driver for the Loongson 3A low-end IO controller. + * + * Each Loongson 3A CPU package has a built-in `low-end' IO controller. + * The controller provides GPIO, LPCI, PCI, SPI, and UART interfaces. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> + +#include <machine/autoconf.h> + +#include <loongson/dev/leiocreg.h> +#include <loongson/dev/leiocvar.h> + +int leioc_match(struct device *, void *, void*); +void leioc_attach(struct device *, struct device *, void *); + +const struct cfattach leioc_ca = { + sizeof(struct device), leioc_match, leioc_attach +}; + +struct cfdriver leioc_cd = { + NULL, "leioc", DV_DULL +}; + +struct mips_bus_space leioc_io_space_tag = { + .bus_base = PHYS_TO_XKPHYS(0, CCA_NC), + ._space_read_1 = generic_space_read_1, + ._space_write_1 = generic_space_write_1, + ._space_map = generic_space_map, + ._space_unmap = generic_space_unmap +}; + +int +leioc_match(struct device *parent, void *cfg, void *aux) +{ + struct mainbus_attach_args *maa = aux; + + if (loongson_ver != 0x3a && loongson_ver != 0x3b) + return 0; + + if (strcmp(maa->maa_name, leioc_cd.cd_name) != 0) + return 0; + + return 1; +} + +void +leioc_attach(struct device *parent, struct device *self, void *aux) +{ + struct leioc_attach_args laa; + + printf("\n"); + + laa.laa_name = "com"; + laa.laa_iot = &leioc_io_space_tag; + laa.laa_base = LEIOC_UART0_BASE; + config_found(self, &laa, NULL); + laa.laa_base = LEIOC_UART1_BASE; + config_found(self, &laa, NULL); +} diff --git a/sys/arch/loongson/dev/leiocreg.h b/sys/arch/loongson/dev/leiocreg.h new file mode 100644 index 00000000000..f24b9988332 --- /dev/null +++ b/sys/arch/loongson/dev/leiocreg.h @@ -0,0 +1,37 @@ +/* $OpenBSD: leiocreg.h,v 1.1 2016/11/17 14:41:21 visa Exp $ */ + +/* + * Copyright (c) 2016 Visa Hankala + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LOONGSON_DEV_LEIOCREG_H_ +#define _LOONGSON_DEV_LEIOCREG_H_ + +#define LEIOC_PCI_CFG_BASE 0x1fe00000 +#define LEIOC_IO_CFG_BASE 0x1fe00100 +#define LEIOC_UART0_BASE 0x1fe001e0 +#define LEIOC_UART1_BASE 0x1fe001e8 +#define LEIOC_SPI_BASE 0x1fe001f0 + +#define LEIOC_LPC_MEM_BASE 0x1c000000 +#define LEIOC_LPC_MEM_SIZE 0x01000000 +#define LEIOC_LPC_BOOT_BASE 0x1fc00000 +#define LEIOC_LPC_BOOT_SIZE 0x00100000 +#define LEIOC_LPC_REG_BASE 0x1fe00200 +#define LEIOC_LPC_REG_SIZE 0x00000100 +#define LEIOC_LPC_IO_BASE 0x1ff00000 +#define LEIOC_LPC_IO_SIZE 0x00010000 + +#endif /* _LOONGSON_DEV_LEIOCREG_H_ */ diff --git a/sys/arch/loongson/dev/leiocvar.h b/sys/arch/loongson/dev/leiocvar.h new file mode 100644 index 00000000000..c9e16b3529f --- /dev/null +++ b/sys/arch/loongson/dev/leiocvar.h @@ -0,0 +1,34 @@ +/* $OpenBSD: leiocvar.h,v 1.1 2016/11/17 14:41:21 visa Exp $ */ + +/* + * Copyright (c) 2016 Visa Hankala + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LOONGSON_DEV_LEIOCVAR_H_ +#define _LOONGSON_DEV_LEIOCVAR_H_ + +struct leioc_attach_args { + paddr_t laa_base; + const char *laa_name; + + bus_space_tag_t laa_iot; + bus_space_handle_t laa_ioh; +}; + +extern struct mips_bus_space leioc_io_space_tag; + +void leioc_cons_setup(void); + +#endif /* _LOONGSON_DEV_LEIOCVAR_H_ */ diff --git a/sys/arch/loongson/dev/mainbus.c b/sys/arch/loongson/dev/mainbus.c index ee8c6b6eff3..87501a88c2e 100644 --- a/sys/arch/loongson/dev/mainbus.c +++ b/sys/arch/loongson/dev/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.8 2013/05/30 16:15:01 deraadt Exp $ */ +/* $OpenBSD: mainbus.c,v 1.9 2016/11/17 14:41:21 visa Exp $ */ /* * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -70,6 +70,12 @@ mainbus_attach(struct device *parent, struct device *self, void *aux) caa.caa_maa.maa_name = "bonito"; config_found(self, &caa.caa_maa, mainbus_print); + caa.caa_maa.maa_name = "htb"; + config_found(self, &caa.caa_maa, mainbus_print); + + caa.caa_maa.maa_name = "leioc"; + config_found(self, &caa.caa_maa, mainbus_print); + if (md_startclock == NULL) { caa.caa_maa.maa_name = "clock"; config_found(self, &caa.caa_maa, mainbus_print); diff --git a/sys/arch/loongson/include/intr.h b/sys/arch/loongson/include/intr.h index 5d8d9fa9e6b..949e33f6b0e 100644 --- a/sys/arch/loongson/include/intr.h +++ b/sys/arch/loongson/include/intr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.h,v 1.9 2016/11/06 10:20:33 visa Exp $ */ +/* $OpenBSD: intr.h,v 1.10 2016/11/17 14:41:21 visa Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -57,7 +57,8 @@ #define IPL_STATCLOCK IPL_CLOCK #define IPL_SCHED 7 /* everything */ #define IPL_HIGH 7 /* everything */ -#define NIPLS 8 /* Number of levels */ +#define IPL_IPI 8 /* interprocessor interrupt */ +#define NIPLS 9 /* Number of levels */ #define IPL_MPFLOOR IPL_TTY diff --git a/sys/arch/loongson/loongson/generic3a_machdep.c b/sys/arch/loongson/loongson/generic3a_machdep.c new file mode 100644 index 00000000000..8d891c28ff0 --- /dev/null +++ b/sys/arch/loongson/loongson/generic3a_machdep.c @@ -0,0 +1,281 @@ +/* $OpenBSD: generic3a_machdep.c,v 1.1 2016/11/17 14:41:21 visa Exp $ */ + +/* + * Copyright (c) 2009, 2010, 2012 Miodrag Vallat. + * Copyright (c) 2016 Visa Hankala. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Generic Loongson 2Gq and 3A code and configuration data. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <mips64/archtype.h> +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <machine/pmon.h> + +#include <mips64/loongson3.h> + +#include <dev/ic/i8259reg.h> +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <loongson/dev/htbreg.h> +#include <loongson/dev/htbvar.h> +#include <loongson/dev/leiocvar.h> + +#define IRQ_CASCADE 2 + +void generic3a_device_register(struct device *, void *); +void generic3a_powerdown(void); +void generic3a_reset(void); +void generic3a_setup(void); + +void rs780e_setup(void); + +void rs780e_isa_attach_hook(struct device *, struct device *, + struct isabus_attach_args *iba); +void *rs780e_isa_intr_establish(void *, int, int, int, int (*)(void *), + void *, char *); +void rs780e_isa_intr_disestablish(void *, void *); + +void rs780e_eoi(int); +void rs780e_set_imask(uint32_t); +void rs780e_irq_mask(int); +void rs780e_irq_unmask(int); + +/* Firmware entry points */ +void (*generic3a_reboot_entry)(void); +void (*generic3a_poweroff_entry)(void); + +struct mips_isa_chipset rs780e_isa_chipset = { + .ic_v = NULL, + .ic_attach_hook = rs780e_isa_attach_hook, + .ic_intr_establish = rs780e_isa_intr_establish, + .ic_intr_disestablish = rs780e_isa_intr_disestablish +}; + +const struct legacy_io_range rs780e_legacy_ranges[] = { + /* isa */ + { IO_DMAPG + 4, IO_DMAPG + 4 }, + /* mcclock */ + { IO_RTC, IO_RTC + 1 }, +#ifdef notyet + /* pciide */ + { 0x170, 0x170 + 7 }, + { 0x1f0, 0x1f0 + 7 }, + { 0x376, 0x376 }, + { 0x3f6, 0x3f6 }, +#endif + /* pckbc */ + { IO_KBD, IO_KBD }, + { IO_KBD + 4, IO_KBD + 4 }, + + { 0, 0 } +}; + +const struct platform rs780e_platform = { + .system_type = LOONGSON_3A, + .vendor = "Loongson", + .product = "LS3A with RS780E", + + .isa_chipset = &rs780e_isa_chipset, + .legacy_io_ranges = rs780e_legacy_ranges, + + .setup = rs780e_setup, + .device_register = generic3a_device_register, + + .powerdown = generic3a_powerdown, + .reset = generic3a_reset +}; + +const struct pic rs780e_pic = { + rs780e_eoi, rs780e_irq_mask, rs780e_irq_unmask +}; + +uint32_t rs780e_imask; + +/* + * Generic 3A routines + */ + +void +generic3a_powerdown(void) +{ + if (generic3a_poweroff_entry != NULL) + generic3a_poweroff_entry(); +} + +void +generic3a_reset(void) +{ + if (generic3a_reboot_entry != NULL) + generic3a_reboot_entry(); +} + +void +generic3a_setup(void) +{ + const struct pmon_env_reset *resetenv = pmon_get_env_reset(); + + if (resetenv != NULL) { + generic3a_reboot_entry = resetenv->warm_boot; + generic3a_poweroff_entry = resetenv->poweroff; + } + + loongson3_intr_init(); +} + +void +generic3a_device_register(struct device *dev, void *aux) +{ +#if notyet + const char *drvrname = dev->dv_cfdata->cf_driver->cd_name; + const char *name = dev->dv_xname; + + if (dev->dv_class != bootdev_class) + return; + + /* + * The device numbering must match. There's no way + * pmon tells us more info. Depending on the usb slot + * and hubs used you may be lucky. Also, assume umass/sd for usb + * attached devices. + */ + switch (bootdev_class) { + case DV_DISK: + if (strcmp(drvrname, "wd") == 0 && strcmp(name, bootdev) == 0) + bootdv = dev; + else { + /* XXX this really only works safely for usb0... */ + if ((strcmp(drvrname, "sd") == 0 || + strcmp(drvrname, "cd") == 0) && + strncmp(bootdev, "usb", 3) == 0 && + strcmp(name + 2, bootdev + 3) == 0) + bootdv = dev; + } + break; + case DV_IFNET: + /* + * This relies on the onboard Ethernet interface being + * attached before any other (usb) interface. + */ + bootdv = dev; + break; + default: + break; + } +#endif +} + +/* + * Routines for RS780E-based systems + */ + +void +rs780e_setup(void) +{ + generic3a_setup(); + + htb_early_setup(); + + /* + * Set up the PIC in the southbridge. + */ + + /* master */ + REGVAL8(HTB_IO_BASE + IO_ICU1 + PIC_ICW1) = ICW1_SELECT | ICW1_IC4; + REGVAL8(HTB_IO_BASE + IO_ICU1 + PIC_ICW2) = ICW2_VECTOR(0); + REGVAL8(HTB_IO_BASE + IO_ICU1 + PIC_ICW3) = ICW3_CASCADE(IRQ_CASCADE); + REGVAL8(HTB_IO_BASE + IO_ICU1 + PIC_ICW4) = ICW4_8086; + REGVAL8(HTB_IO_BASE + IO_ICU1 + PIC_OCW1) = 0xff; + + /* slave */ + REGVAL8(HTB_IO_BASE + IO_ICU2 + PIC_ICW1) = ICW1_SELECT | ICW1_IC4; + REGVAL8(HTB_IO_BASE + IO_ICU2 + PIC_ICW2) = ICW2_VECTOR(8); + REGVAL8(HTB_IO_BASE + IO_ICU2 + PIC_ICW3) = ICW3_SIC(IRQ_CASCADE); + REGVAL8(HTB_IO_BASE + IO_ICU2 + PIC_ICW4) = ICW4_8086; + REGVAL8(HTB_IO_BASE + IO_ICU2 + PIC_OCW1) = 0xff; + + loongson3_register_ht_pic(&rs780e_pic); +} + +void +rs780e_isa_attach_hook(struct device *parent, struct device *self, + struct isabus_attach_args *iba) +{ +} + +void * +rs780e_isa_intr_establish(void *v, int irq, int type, int level, + int (*cb)(void *), void *cbarg, char *name) +{ + return loongson3_ht_intr_establish(irq, level, cb, cbarg, name); +} + +void +rs780e_isa_intr_disestablish(void *v, void *ih) +{ + loongson3_ht_intr_disestablish(ih); +} + +void +rs780e_eoi(int irq) +{ + KASSERT((unsigned int)irq <= 15); + + if (irq & 8) { + REGVAL8(HTB_IO_BASE + IO_ICU2 + PIC_OCW2) = + OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq); + irq = IRQ_CASCADE; + } + REGVAL8(HTB_IO_BASE + IO_ICU1 + PIC_OCW2) = + OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq); +} + +void +rs780e_set_imask(uint32_t new_imask) +{ + uint8_t imr1, imr2; + + imr1 = 0xff & ~new_imask; + imr1 &= ~(1u << IRQ_CASCADE); + imr2 = 0xff & ~(new_imask >> 8); + + REGVAL8(HTB_IO_BASE + IO_ICU2 + PIC_OCW1) = imr2; + REGVAL8(HTB_IO_BASE + IO_ICU1 + PIC_OCW1) = imr1; + + rs780e_imask = new_imask; +} + +void +rs780e_irq_mask(int irq) +{ + rs780e_set_imask(rs780e_imask & ~(1u << irq)); +} + +void +rs780e_irq_unmask(int irq) +{ + rs780e_set_imask(rs780e_imask | (1u << irq)); +} diff --git a/sys/arch/loongson/loongson/machdep.c b/sys/arch/loongson/loongson/machdep.c index 8a7f79ffb0e..0f65dd05e95 100644 --- a/sys/arch/loongson/loongson/machdep.c +++ b/sys/arch/loongson/loongson/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.67 2016/10/09 11:25:39 tom Exp $ */ +/* $OpenBSD: machdep.c,v 1.68 2016/11/17 14:41:21 visa Exp $ */ /* * Copyright (c) 2009, 2010, 2014 Miodrag Vallat. @@ -114,6 +114,7 @@ caddr_t msgbufbase; int physmem; /* Max supported memory, changes to actual. */ int ncpu = 1; /* At least one CPU in the system. */ +int nnodes = 1; /* Number of NUMA nodes, only on 3A. */ struct user *proc0paddr; const struct platform *sys_platform; @@ -142,6 +143,8 @@ extern void parsepmonbp(void); const struct platform *loongson_identify(const char *, int); vaddr_t mips_init(uint64_t, uint64_t, uint64_t, uint64_t, char *); +extern void htb_early_setup(void); + extern void loongson2e_setup(u_long, u_long); extern void loongson2f_setup(u_long, u_long); extern void loongson3a_setup(u_long, u_long); @@ -173,8 +176,8 @@ extern const struct platform ebenton_platform; extern const struct platform fuloong_platform; extern const struct platform gdium_platform; extern const struct platform generic2e_platform; -extern const struct platform lemote3a_platform; extern const struct platform lynloong_platform; +extern const struct platform rs780e_platform; extern const struct platform yeeloong_platform; const struct bonito_flavour bonito_flavours[] = { @@ -198,12 +201,12 @@ const struct bonito_flavour bonito_flavours[] = { #endif #ifdef CPU_LOONGSON3 /* Laptops */ - { "A1004", &lemote3a_platform }, /* 3A */ - { "A1201", &lemote3a_platform }, /* 2Gq */ + { "A1004", &rs780e_platform }, /* 3A */ + { "A1201", &rs780e_platform }, /* 2Gq */ /* Lemote Xinghuo 6100 (mini-ITX PC) */ - { "A1101", &lemote3a_platform }, /* 3A */ + { "A1101", &rs780e_platform }, /* 3A */ /* All-in-one PC */ - { "A1205", &lemote3a_platform }, /* 2Gq */ + { "A1205", &rs780e_platform }, /* 2Gq */ #endif { NULL } }; @@ -220,7 +223,23 @@ loongson_identify(const char *version, int envtype) switch (envtype) { #ifdef CPU_LOONGSON3 case PMON_ENVTYPE_EFI: - return &lemote3a_platform; + if (loongson_ver == 0x3a || loongson_ver == 0x3b) { + pcitag_t tag; + pcireg_t id; + + htb_early_setup(); + + /* Determine platform by host bridge. */ + tag = pci_make_tag_early(0, 0, 0); + id = pci_conf_read_early(tag, PCI_ID_REG); + switch (id) { + case PCI_ID_CODE(PCI_VENDOR_AMD, + PCI_PRODUCT_AMD_RS780_HB): + return &rs780e_platform; + } + } + pmon_printf("Unable to figure out model!\n"); + return NULL; #endif default: |