From b67fd34c0fd3423bba8606da54914d5c8f9bbc36 Mon Sep 17 00:00:00 2001 From: uch Date: Mon, 11 Feb 2002 17:27:15 +0000 Subject: [PATCH] HD64465 interrupt, uart, pcmcia modules --- sys/arch/hpcsh/dev/hd64465/hd64465.c | 290 +++++++ sys/arch/hpcsh/dev/hd64465/hd64465intcreg.h | 61 ++ sys/arch/hpcsh/dev/hd64465/hd64465pcmcia.c | 841 ++++++++++++++++++++ sys/arch/hpcsh/dev/hd64465/hd64465reg.h | 86 ++ sys/arch/hpcsh/dev/hd64465/hd64465uart.c | 196 +++++ sys/arch/hpcsh/dev/hd64465/hd64465uartvar.h | 60 ++ sys/arch/hpcsh/dev/hd64465/hd64465var.h | 95 +++ 7 files changed, 1629 insertions(+) create mode 100644 sys/arch/hpcsh/dev/hd64465/hd64465.c create mode 100644 sys/arch/hpcsh/dev/hd64465/hd64465intcreg.h create mode 100644 sys/arch/hpcsh/dev/hd64465/hd64465pcmcia.c create mode 100644 sys/arch/hpcsh/dev/hd64465/hd64465reg.h create mode 100644 sys/arch/hpcsh/dev/hd64465/hd64465uart.c create mode 100644 sys/arch/hpcsh/dev/hd64465/hd64465uartvar.h create mode 100644 sys/arch/hpcsh/dev/hd64465/hd64465var.h diff --git a/sys/arch/hpcsh/dev/hd64465/hd64465.c b/sys/arch/hpcsh/dev/hd64465/hd64465.c new file mode 100644 index 000000000000..a45a6b2c430c --- /dev/null +++ b/sys/arch/hpcsh/dev/hd64465/hd64465.c @@ -0,0 +1,290 @@ +/* $NetBSD: hd64465.c,v 1.1 2002/02/11 17:27:15 uch Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +/* HD64465 modules. */ +STATIC const struct hd64465_module { + const char *name; +} hd64465_modules[] = { + [HD64465_MODULE_PS2IF] = { "hd64465ps2if" }, + [HD64465_MODULE_PCMCIA] = { "hd64465pcmcia" }, + [HD64465_MODULE_AFE] = { "hd64465afe" }, + [HD64465_MODULE_GPIO] = { "hd64465gpio" }, + [HD64465_MODULE_KBC] = { "hd64465kbc" }, + [HD64465_MODULE_IRDA] = { "hd64465irda" }, + [HD64465_MODULE_UART] = { "hd64465uart" }, + [HD64465_MODULE_PARALEL] = { "hd64465paralel" }, + [HD64465_MODULE_CODEC] = { "hd64465codec" }, + [HD64465_MODULE_OHCI] = { "hd64465ohci" }, + [HD64465_MODULE_ADC] = { "hd64465adc" } +}; +#define HD64465_NMODULE \ + (sizeof hd64465_modules / sizeof(struct hd64465_module)) + +STATIC struct hd64465_intr_entry { + int (*func)(void *); + void *arg; + int priority; + const u_int16_t bit; +} hd64465_intr_entry[] = { +#define IRQ_ENTRY(x) [HD64465_IRQ_ ## x] = { 0, 0, 0, HD64465_ ## x } + IRQ_ENTRY(PS2KB), + IRQ_ENTRY(PCC0), + IRQ_ENTRY(PCC1), + IRQ_ENTRY(AFE), + IRQ_ENTRY(GPIO), + IRQ_ENTRY(TMU0), + IRQ_ENTRY(TMU1), + IRQ_ENTRY(KBC), + IRQ_ENTRY(PS2MS), + IRQ_ENTRY(IRDA), + IRQ_ENTRY(UART), + IRQ_ENTRY(PPR), + IRQ_ENTRY(SCDI), + IRQ_ENTRY(OHCI), + IRQ_ENTRY(ADC) +#undef IRQ_ENTRY +}; +#define HD64465_IRQ_MAX \ + (sizeof hd64465_intr_entry / sizeof(struct hd64465_intr_entry)) + +STATIC struct hd64465 { + int attached; + u_int16_t imask; +} hd64465; + +STATIC int hd64465_match(struct device *, struct cfdata *, void *); +STATIC void hd64465_attach(struct device *, struct device *, void *); +STATIC int hd64465_print(void *, const char *); +STATIC int hd64465_intr(void *); + +struct cfattach hd64465if_ca = { + sizeof(struct device), hd64465_match, hd64465_attach +}; + +int +hd64465_match(struct device *parent, struct cfdata *cf, void *aux) +{ + + if (hd64465.attached++) + return (0); /* only one instance */ + + if (strcmp("hd64465if", cf->cf_driver->cd_name)) + return (0); + + if (hd64465_reg_read_2(HD64465_SDIDR) != 0x8122) { + /* not HD64465 */ + return (0); + } + + return (1); +} + +void +hd64465_attach(struct device *parent, struct device *self, void *aux) +{ + struct shb_attach_args *ia = aux; + const struct hd64465_module *module; + struct hd64465_attach_args ha; + u_int16_t r; + int i; + + printf("\n"); + + r = hd64465_reg_read_2(HD64465_SRR); + printf("%s: HITACHI HD64465 rev. %d.%d\n", self->dv_xname, + (r >> 8) & 0xff, r & 0xff); + + hd64465_intr_disable(); + + /* Attach all sub modules */ + for (i = 0, module = hd64465_modules; i < HD64465_NMODULE; + i++, module++) { + if (module->name == 0) + continue; + ha.ha_module_id = i; + config_found(self, &ha, hd64465_print); + } + + shb_intr_establish(ia->ia_irq, IST_EDGE, IPL_TTY, hd64465_intr, self); +} + +int +hd64465_print(void *aux, const char *pnp) +{ + struct hd64465_attach_args *ha = aux; + + if (pnp) + printf("%s at %s", hd64465_modules[ha->ha_module_id].name, pnp); + + return (UNCONF); +} + +void * +hd64465_intr_establish(enum hd64465_irq irq, int mode, int level, + int (*func)(void *), void *arg) +{ + struct hd64465_intr_entry *entry = &hd64465_intr_entry[irq]; + u_int16_t r, bit; + int s; + + s = splhigh(); + + entry->func = func; + entry->arg = arg; + entry->priority = level; + + bit = entry->bit; + + /* Trigger type */ + r = hd64465_reg_read_2(HD64465_NITR); + switch (mode) { + case IST_PULSE: + /* FALLTHROUGH */ + case IST_EDGE: + r |= bit; + break; + case IST_LEVEL: + r &= ~bit; + break; + } + hd64465_reg_write_2(HD64465_NITR, r); + + /* Enable interrupt */ + hd64465.imask &= ~bit; + hd64465_reg_write_2(HD64465_NIMR, hd64465.imask); + + splx(s); + + return (void *)irq; +} + +void +hd64465_intr_disestablish(void *handle) +{ + int irq = (int)handle; + struct hd64465_intr_entry *entry = &hd64465_intr_entry[irq]; + int s; + + s = splhigh(); + + /* disable interrupt */ + hd64465.imask |= entry->bit; + hd64465_reg_write_2(HD64465_NIMR, hd64465.imask); + + entry->func = 0; + + splx(s); +} + +int +hd64465_intr(void *arg) +{ + struct hd64465_intr_entry *entry = hd64465_intr_entry; + u_int16_t cause; + int i; + + cause = hd64465_reg_read_2(HD64465_NIRR) & ~hd64465.imask; + hd64465_reg_write_2(HD64465_NIRR, 0); + + for (i = 0; i < HD64465_IRQ_MAX; i++, entry++) { + if (entry->func == 0) + continue; + if (cause & entry->bit) + (*entry->func)(entry->arg); + } + + __dbg_heart_beat(HEART_BEAT_BLUE); + + return (0); +} + +void +hd64465_intr_disable() +{ + + /* Mask all interrupt */ + hd64465.imask = 0xffff; + hd64465_reg_write_2(HD64465_NIMR, 0xffff); + + /* Edge trigger mode */ + hd64465_reg_write_2(HD64465_NITR, 0xffff); + /* Clear pending interrupt */ + hd64465_reg_write_2(HD64465_NIRR, 0x0000); +} + +void +hd64465_intr_mask() +{ + + hd64465_reg_write_2(HD64465_NIMR, 0xffff); +} + +void +hd64465_intr_unmask() +{ + + hd64465_reg_write_2(HD64465_NIMR, hd64465.imask); +} + +/* For the sake of Windows CE reboot clearly. */ +void +hd64465_intr_reboot() +{ + + /* Enable all interrupt */ + hd64465_reg_write_2(HD64465_NIMR, 0x0000); + + /* Level trigger mode */ + hd64465_reg_write_2(HD64465_NITR, 0x0000); +} diff --git a/sys/arch/hpcsh/dev/hd64465/hd64465intcreg.h b/sys/arch/hpcsh/dev/hd64465/hd64465intcreg.h new file mode 100644 index 000000000000..9f9b734f6ccc --- /dev/null +++ b/sys/arch/hpcsh/dev/hd64465/hd64465intcreg.h @@ -0,0 +1,61 @@ +/* $NetBSD: hd64465intcreg.h,v 1.1 2002/02/11 17:27:15 uch Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Interrupt Request Register (16bit) */ +#define HD64465_NIRR 0xb0005000 +/* Interrupt Mask Register (16bit) */ +#define HD64465_NIMR 0xb0005002 +/* Interrupt Trigger Mode Register (16bit) */ +#define HD64465_NITR 0xb0005004 + +/* common defines. */ +#define HD64465_PS2KB 0x8000 +#define HD64465_PCC0 0x4000 +#define HD64465_PCC1 0x2000 +#define HD64465_AFE 0x1000 +#define HD64465_GPIO 0x0800 +#define HD64465_TMU0 0x0400 +#define HD64465_TMU1 0x0200 +#define HD64465_KBC 0x0100 +#define HD64465_PS2MS 0x0080 +#define HD64465_IRDA 0x0040 +#define HD64465_UART 0x0020 +#define HD64465_PPR 0x0008 +#define HD64465_SCDI 0x0004 +#define HD64465_OHCI 0x0002 +#define HD64465_ADC 0x0001 diff --git a/sys/arch/hpcsh/dev/hd64465/hd64465pcmcia.c b/sys/arch/hpcsh/dev/hd64465/hd64465pcmcia.c new file mode 100644 index 000000000000..d8f1ee70a262 --- /dev/null +++ b/sys/arch/hpcsh/dev/hd64465/hd64465pcmcia.c @@ -0,0 +1,841 @@ +/* $NetBSD: hd64465pcmcia.c,v 1.1 2002/02/11 17:27:16 uch Exp $ */ + +/*- + * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include "locators.h" + +#ifdef HD64465PCMCIA_DEBUG +#define DPRINTF_ENABLE +#define DPRINTF_DEBUG hd64465pcmcia_debug +#endif +#include + +enum memory_window_16 { + MEMWIN_16M_COMMON_0, + MEMWIN_16M_COMMON_1, + MEMWIN_16M_COMMON_2, + MEMWIN_16M_COMMON_3, +}; +#define MEMWIN_16M_MAX 4 + +enum hd64465pcmcia_event_type { + EVENT_NONE, + EVENT_INSERT, + EVENT_REMOVE, +}; +#define EVENT_QUEUE_MAX 5 + +struct hd64465pcmcia_softc; /* forward declaration */ + +struct hd64465pcmcia_window_cookie { + bus_space_tag_t wc_tag; + bus_space_handle_t wc_handle; + int wc_size; + int wc_window; +}; + +struct hd64465pcmcia_channel { + struct hd64465pcmcia_softc *ch_parent; + struct device *ch_pcmcia; + int ch_channel; + + /* memory space */ + bus_space_tag_t ch_memt; + bus_space_handle_t ch_memh; + bus_addr_t ch_membase_addr; + bus_size_t ch_memsize; + bus_space_tag_t ch_cmemt[MEMWIN_16M_MAX]; + + /* I/O space */ + bus_space_tag_t ch_iot; + bus_addr_t ch_iobase; + bus_size_t ch_iosize; + + /* card interrupt */ + int (*ch_ih_card_func)(void *); + void *ch_ih_card_arg; + int ch_attached; +}; + +struct hd64465pcmcia_event { + int __queued; + enum hd64465pcmcia_event_type pe_type; + struct hd64465pcmcia_channel *pe_ch; + SIMPLEQ_ENTRY(hd64465pcmcia_event) pe_link; +}; + +struct hd64465pcmcia_softc { + struct device sc_dev; + enum hd64465_module_id sc_module_id; + int sc_shutdown; + + /* kv mapped Area 5, 6 */ + vaddr_t sc_area5; + vaddr_t sc_area6; + + /* CSC event */ + struct proc *sc_event_thread; + struct hd64465pcmcia_event sc_event_pool[EVENT_QUEUE_MAX]; + SIMPLEQ_HEAD (, hd64465pcmcia_event) sc_event_head; + + struct hd64465pcmcia_channel sc_ch[2]; +}; + +STATIC int hd64465pcmcia_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t, + struct pcmcia_mem_handle *); +STATIC void hd64465pcmcia_chip_mem_free(pcmcia_chipset_handle_t, + struct pcmcia_mem_handle *); +STATIC int hd64465pcmcia_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, + bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *); +STATIC void hd64465pcmcia_chip_mem_unmap(pcmcia_chipset_handle_t, int); +STATIC int hd64465pcmcia_chip_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, + bus_size_t, bus_size_t, struct pcmcia_io_handle *); +STATIC void hd64465pcmcia_chip_io_free(pcmcia_chipset_handle_t, + struct pcmcia_io_handle *); +STATIC int hd64465pcmcia_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, + bus_size_t, struct pcmcia_io_handle *, int *); +STATIC void hd64465pcmcia_chip_io_unmap(pcmcia_chipset_handle_t, int); +STATIC void hd64465pcmcia_chip_socket_enable(pcmcia_chipset_handle_t); +STATIC void hd64465pcmcia_chip_socket_disable(pcmcia_chipset_handle_t); +STATIC void *hd64465pcmcia_chip_intr_establish(pcmcia_chipset_handle_t, + struct pcmcia_function *, int, int (*)(void *), void *); +STATIC void hd64465pcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t, + void *); + +STATIC struct pcmcia_chip_functions hd64465pcmcia_functions = { + hd64465pcmcia_chip_mem_alloc, + hd64465pcmcia_chip_mem_free, + hd64465pcmcia_chip_mem_map, + hd64465pcmcia_chip_mem_unmap, + hd64465pcmcia_chip_io_alloc, + hd64465pcmcia_chip_io_free, + hd64465pcmcia_chip_io_map, + hd64465pcmcia_chip_io_unmap, + hd64465pcmcia_chip_intr_establish, + hd64465pcmcia_chip_intr_disestablish, + hd64465pcmcia_chip_socket_enable, + hd64465pcmcia_chip_socket_disable, +}; + +STATIC int hd64465pcmcia_match(struct device *, struct cfdata *, void *); +STATIC void hd64465pcmcia_attach(struct device *, struct device *, void *); +STATIC int hd64465pcmcia_print(void *, const char *); +STATIC int hd64465pcmcia_submatch(struct device *, struct cfdata *, void *); + +struct cfattach hd64465pcmcia_ca = { + sizeof(struct hd64465pcmcia_softc), hd64465pcmcia_match, + hd64465pcmcia_attach +}; + +STATIC void hd64465pcmcia_attach_channel(struct hd64465pcmcia_softc *, int); +/* hot plug */ +STATIC void hd64465pcmcia_create_event_thread(void *); +STATIC void hd64465pcmcia_event_thread(void *); +STATIC void queue_event(struct hd64465pcmcia_channel *, + enum hd64465pcmcia_event_type); +/* interrupt handler */ +STATIC int hd64465pcmcia_intr(void *); +/* card status */ +STATIC enum hd64465pcmcia_event_type detect_card(int); +STATIC void hd64465pcmcia_memory_window16_switch(int, enum memory_window_16); +/* bus width */ +STATIC void __sh_set_bus_width(int, int); +/* bus space access */ +STATIC int __sh_hd64465_map(vaddr_t, paddr_t, size_t, u_int32_t); +STATIC vaddr_t __sh_hd64465_map_2page(paddr_t); + +#define DELAY_MS(x) delay((x) * 1000) + +int +hd64465pcmcia_match(struct device *parent, struct cfdata *cf, void *aux) +{ + struct hd64465_attach_args *ha = aux; + + return (ha->ha_module_id == HD64465_MODULE_PCMCIA); +} + +void +hd64465pcmcia_attach(struct device *parent, struct device *self, void *aux) +{ + struct hd64465_attach_args *ha = aux; + struct hd64465pcmcia_softc *sc = (struct hd64465pcmcia_softc *)self; + + sc->sc_module_id = ha->ha_module_id; + + printf("\n"); + + sc->sc_area5 = __sh_hd64465_map_2page(0x14000000); /* area 5 */ + sc->sc_area6 = __sh_hd64465_map_2page(0x18000000); /* area 6 */ + + if (sc->sc_area5 == NULL || sc->sc_area6 == NULL) { + printf("%s: can't map memory.\n", sc->sc_dev.dv_xname); + if (sc->sc_area5) + uvm_km_free(kernel_map, sc->sc_area5, 0x03000000); + if (sc->sc_area6) + uvm_km_free(kernel_map, sc->sc_area6, 0x03000000); + + return; + } + + /* Channel 0/1 common CSC event queue */ + SIMPLEQ_INIT (&sc->sc_event_head); + kthread_create(hd64465pcmcia_create_event_thread, sc); + + hd64465pcmcia_attach_channel(sc, 0); + hd64465pcmcia_attach_channel(sc, 1); +} + +void +hd64465pcmcia_create_event_thread(void *arg) +{ + struct hd64465pcmcia_softc *sc = arg; + int error; + + error = kthread_create1(hd64465pcmcia_event_thread, sc, + &sc->sc_event_thread, "%s", sc->sc_dev.dv_xname); + + KASSERT(error == 0); +} + +void +hd64465pcmcia_event_thread(void *arg) +{ + struct hd64465pcmcia_softc *sc = arg; + struct hd64465pcmcia_event *pe; + int s; + + while (!sc->sc_shutdown) { + tsleep(sc, PWAIT, "CSC wait", 0); + s = splhigh(); + while ((pe = SIMPLEQ_FIRST(&sc->sc_event_head))) { + splx(s); + switch (pe->pe_type) { + default: + printf("%s: unknown event.\n", __FUNCTION__); + break; + case EVENT_INSERT: + DPRINTF("insert event.\n"); + pcmcia_card_attach(pe->pe_ch->ch_pcmcia); + break; + case EVENT_REMOVE: + DPRINTF("remove event.\n"); + pcmcia_card_detach(pe->pe_ch->ch_pcmcia, + DETACH_FORCE); + break; + } + s = splhigh(); + SIMPLEQ_REMOVE_HEAD(&sc->sc_event_head, pe, pe_link); + pe->__queued = 0; + } + splx(s); + } + /* NOTREACHED */ +} + +int +hd64465pcmcia_print(void *arg, const char *pnp) +{ + + if (pnp) + printf("pcmcia at %s", pnp); + + return (UNCONF); +} + +int +hd64465pcmcia_submatch(struct device *parent, struct cfdata *cf, void *aux) +{ + struct pcmciabus_attach_args *paa = aux; + struct hd64465pcmcia_channel *ch = + (struct hd64465pcmcia_channel *)paa->pch; + + if (ch->ch_channel == 0) { + if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] != + PCMCIABUSCF_CONTROLLER_DEFAULT && + cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 0) + return 0; + } else { + if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] != + PCMCIABUSCF_CONTROLLER_DEFAULT && + cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 1) + return 0; + } + paa->pct = (pcmcia_chipset_tag_t)&hd64465pcmcia_functions; + + return ((*cf->cf_attach->ca_match)(parent, cf, aux)); +} + +void +hd64465pcmcia_attach_channel(struct hd64465pcmcia_softc *sc, int channel) +{ + struct device *parent = (struct device *)sc; + struct hd64465pcmcia_channel *ch = &sc->sc_ch[channel]; + struct pcmciabus_attach_args paa; + bus_addr_t baseaddr; + u_int8_t r; + int i; + + ch->ch_parent = sc; + ch->ch_channel = channel; + + /* + * Continuous 16-MB Area Mode + */ + /* set Continuous 16-MB Area Mode */ + r = hd64465_reg_read_1(HD64461_PCCGCR(channel)); + r &= ~HD64461_PCCGCR_MMOD; + r |= HD64461_PCCGCR_MMOD_16M; + hd64465_reg_write_1(HD64461_PCCGCR(channel), r); + + /* Attibute/Common memory extent */ + baseaddr = (channel == 0) ? sc->sc_area6 : sc->sc_area5; + + ch->ch_memt = bus_space_create(0, "PCMCIA attribute memory", + baseaddr, 0x01000000); /* 16MB */ + bus_space_alloc(ch->ch_memt, 0, 0x00ffffff, 0x0001000, + 0x1000, 0x1000, 0, &ch->ch_membase_addr, &ch->ch_memh); + + /* Common memory space extent */ + ch->ch_memsize = 0x01000000; + for (i = 0; i < MEMWIN_16M_MAX; i++) { + ch->ch_cmemt[i] = bus_space_create(0, "PCMCIA common memory", + baseaddr + 0x01000000, ch->ch_memsize); + } + + /* I/O port extent */ + ch->ch_iobase = 0; + ch->ch_iosize = 0x01000000; + ch->ch_iot = bus_space_create(0, "PCMCIA I/O port", + baseaddr + 0x01000000 * 2, ch->ch_iosize); + + /* Interrupt */ + hd64465_intr_establish(channel ? HD64465_IRQ_PCC1 : HD64465_IRQ_PCC0, + IST_EDGE, IPL_TTY, hd64465pcmcia_intr, ch); + + paa.paa_busname = "pcmcia"; + paa.pch = (pcmcia_chipset_handle_t)ch; + paa.iobase = ch->ch_iobase; + paa.iosize = ch->ch_iosize; + + ch->ch_pcmcia = config_found_sm(parent, &paa, hd64465pcmcia_print, + hd64465pcmcia_submatch); + + if (ch->ch_pcmcia && (detect_card(ch->ch_channel) == EVENT_INSERT)) { + ch->ch_attached = 1; + pcmcia_card_attach(ch->ch_pcmcia); + } +} + +int +hd64465pcmcia_intr(void *arg) +{ + struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)arg; + u_int32_t cscr; + u_int8_t r; + int ret = 0; + + cscr = HD64461_PCCCSCR(ch->ch_channel); + r = hd64465_reg_read_1(cscr); + + /* clear interrtupt (don't change power switch select) */ + hd64465_reg_write_1(cscr, r & ~0x40); + + if (r & (0x60 | 0x04/* for memory mapped mode*/)) { + if (ch->ch_ih_card_func) { + ret = (*ch->ch_ih_card_func)(ch->ch_ih_card_arg); + } else { + DPRINTF("spurious IREQ interrupt.\n"); + } + } + + if (r & HD64461_PCC0CSCR_P0CDC) + queue_event(ch, detect_card(ch->ch_channel)); + + return (ret); +} + +void +queue_event(struct hd64465pcmcia_channel *ch, + enum hd64465pcmcia_event_type type) +{ + struct hd64465pcmcia_event *pe, *pool; + struct hd64465pcmcia_softc *sc = ch->ch_parent; + int i; + int s = splhigh(); + + if (type == EVENT_NONE) + goto out; + + pe = 0; + pool = sc->sc_event_pool; + for (i = 0; i < EVENT_QUEUE_MAX; i++) { + if (!pool[i].__queued) { + pe = &pool[i]; + break; + } + } + + if (pe == 0) { + printf("%s: event FIFO overflow (max %d).\n", __FUNCTION__, + EVENT_QUEUE_MAX); + goto out; + } + + if ((ch->ch_attached && (type == EVENT_INSERT)) || + (!ch->ch_attached && (type == EVENT_REMOVE))) { + DPRINTF("spurious CSC interrupt.\n"); + goto out; + } + + ch->ch_attached = (type == EVENT_INSERT); + pe->__queued = 1; + pe->pe_type = type; + pe->pe_ch = ch; + SIMPLEQ_INSERT_TAIL(&sc->sc_event_head, pe, pe_link); + wakeup(sc); + out: + splx(s); +} + +/* + * Interface for pcmcia driver. + */ +/* + * Interrupt. + */ +void * +hd64465pcmcia_chip_intr_establish(pcmcia_chipset_handle_t pch, + struct pcmcia_function *pf, int ipl, int (*ih_func)(void *), void *ih_arg) +{ + struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; + int channel = ch->ch_channel; + bus_addr_t cscier = HD64461_PCCCSCIER(channel); + u_int8_t r; + int s = splhigh(); + + ch->ch_ih_card_func = ih_func; + ch->ch_ih_card_arg = ih_arg; + + /* Enable card interrupt */ + r = hd64465_reg_read_1(cscier); + /* set level mode */ + r &= ~HD64461_PCC0CSCIER_P0IREQE_MASK; + r |= HD64461_PCC0CSCIER_P0IREQE_LEVEL; + hd64465_reg_write_1(cscier, r); + + splx(s); + + return (void *)ih_func; +} + +void +hd64465pcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih) +{ + struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; + int channel = ch->ch_channel; + bus_addr_t cscier = HD64461_PCCCSCIER(channel); + int s = splhigh(); + u_int8_t r; + + /* Disable card interrupt */ + r = hd64465_reg_read_1(cscier); + r &= ~HD64461_PCC0CSCIER_P0IREQE_MASK; + r |= HD64461_PCC0CSCIER_P0IREQE_NONE; + hd64465_reg_write_1(cscier, r); + + ch->ch_ih_card_func = 0; + + splx(s); +} + +/* + * Bus resources. + */ +int +hd64465pcmcia_chip_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size, + struct pcmcia_mem_handle *pcmhp) +{ + struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; + + pcmhp->memt = ch->ch_memt; + pcmhp->addr = ch->ch_membase_addr; + pcmhp->memh = ch->ch_memh; + pcmhp->size = size; + pcmhp->realsize = size; + + DPRINTF("base 0x%08lx size %#lx\n", pcmhp->addr, size); + + return (0); +} + +void +hd64465pcmcia_chip_mem_free(pcmcia_chipset_handle_t pch, + struct pcmcia_mem_handle *pcmhp) +{ + /* NO-OP */ +} + +int +hd64465pcmcia_chip_mem_map(pcmcia_chipset_handle_t pch, int kind, + bus_addr_t card_addr, bus_size_t size, struct pcmcia_mem_handle *pcmhp, + bus_size_t *offsetp, int *windowp) +{ + struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; + struct hd64465pcmcia_window_cookie *cookie; + bus_addr_t ofs; + + cookie = malloc(sizeof(struct hd64465pcmcia_window_cookie), + M_DEVBUF, M_NOWAIT); + KASSERT(cookie); + memset(cookie, 0, sizeof(struct hd64465pcmcia_window_cookie)); + + /* Address */ + if ((kind & ~PCMCIA_WIDTH_MEM_MASK) == PCMCIA_MEM_ATTR) { + cookie->wc_tag = ch->ch_memt; + if (bus_space_subregion(ch->ch_memt, ch->ch_memh, card_addr, + size, &cookie->wc_handle) != 0) + goto bad; + + *offsetp = card_addr; + cookie->wc_window = -1; + } else { + int window = card_addr / ch->ch_memsize; + KASSERT(window < MEMWIN_16M_MAX); + + cookie->wc_tag = ch->ch_cmemt[window]; + ofs = card_addr - window * ch->ch_memsize; + if (bus_space_map(cookie->wc_tag, ofs, size, 0, + &cookie->wc_handle) != 0) + goto bad; + + /* XXX bogus. check window per common memory access. */ + hd64465pcmcia_memory_window16_switch(ch->ch_channel, window); + *offsetp = ofs + 0x01000000; /* skip attribute area */ + cookie->wc_window = window; + } + cookie->wc_size = size; + *windowp = (int)cookie; + + DPRINTF("(%s) %#lx+%#lx-> %#lx+%#lx\n", kind == PCMCIA_MEM_ATTR ? + "attribute" : "common", ch->ch_memh, card_addr, *offsetp, size); + + return (0); + bad: + DPRINTF("%#lx-%#lx map failed.\n", card_addr, size); + free(cookie, M_DEVBUF); + + return (1); +} + +void +hd64465pcmcia_chip_mem_unmap(pcmcia_chipset_handle_t pch, int window) +{ + struct hd64465pcmcia_window_cookie *cookie = (void *)window; + + if (cookie->wc_window != -1) + bus_space_unmap(cookie->wc_tag, cookie->wc_handle, + cookie->wc_size); + DPRINTF("%#lx-%#x\n", cookie->wc_handle, cookie->wc_size); + free(cookie, M_DEVBUF); +} + +int +hd64465pcmcia_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, + bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pcihp) +{ + struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; + + if (start) { + if (bus_space_map(ch->ch_iot, start, size, 0, &pcihp->ioh)) { + DPRINTF("couldn't map %#lx+%#lx\n", start, size); + return (1); + } + pcihp->addr = pcihp->ioh; + DPRINTF("map %#lx+%#lx\n", start, size); + } else { + if (bus_space_alloc(ch->ch_iot, ch->ch_iobase, + ch->ch_iobase + ch->ch_iosize - 1, + size, align, 0, 0, &pcihp->addr, &pcihp->ioh)) { + DPRINTF("couldn't allocate %#lx\n", size); + return (1); + } + pcihp->flags = PCMCIA_IO_ALLOCATED; + } + DPRINTF("%#lx from %#lx\n", size, pcihp->addr); + + pcihp->iot = ch->ch_iot; + pcihp->size = size; + + return (0); +} + +int +hd64465pcmcia_chip_io_map(pcmcia_chipset_handle_t pch, int width, + bus_addr_t offset, bus_size_t size, struct pcmcia_io_handle *pcihp, + int *windowp) +{ + struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; +#ifdef HD64465PCMCIA_DEBUG + static const char *width_names[] = { "auto", "io8", "io16" }; +#endif + + __sh_set_bus_width(ch->ch_channel, width); + + DPRINTF("%#lx:%#lx+%#lx %s\n", pcihp->ioh, offset, size, + width_names[width]); + + return (0); +} + +void +hd64465pcmcia_chip_io_free(pcmcia_chipset_handle_t pch, + struct pcmcia_io_handle *pcihp) +{ + + if (pcihp->flags & PCMCIA_IO_ALLOCATED) + bus_space_free(pcihp->iot, pcihp->ioh, pcihp->size); + else + bus_space_unmap(pcihp->iot, pcihp->ioh, pcihp->size); + + DPRINTF("%#lx+%#lx\n", pcihp->ioh, pcihp->size); +} + +void +hd64465pcmcia_chip_io_unmap(pcmcia_chipset_handle_t pch, int window) +{ + /* nothing to do */ +} + +/* + * Enable/Disable + */ +void +hd64465pcmcia_chip_socket_enable(pcmcia_chipset_handle_t pch) +{ + struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; + int channel = ch->ch_channel; + bus_addr_t isr, gcr; + u_int8_t r; + int cardtype; + + DPRINTF("enable channel %d\n", channel); + isr = HD64461_PCCISR(channel); + gcr = HD64461_PCCGCR(channel); + + /* Set Common memory area #0. */ + hd64465pcmcia_memory_window16_switch(channel, MEMWIN_16M_COMMON_0); + + /* Set the card type */ + cardtype = pcmcia_card_gettype(ch->ch_pcmcia); + + r = hd64465_reg_read_1(gcr); + if (cardtype == PCMCIA_IFTYPE_IO) + r |= HD64461_PCC0GCR_P0PCCT; + else + r &= ~HD64461_PCC0GCR_P0PCCT; + hd64465_reg_write_1(gcr, r); + + DPRINTF("OK.\n"); +} + +void +hd64465pcmcia_chip_socket_disable(pcmcia_chipset_handle_t pch) +{ + struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; + int channel = ch->ch_channel; + + /* dont' disable CSC interrupt */ + hd64465_reg_write_1(HD64461_PCCCSCIER(channel), HD64461_PCCCSCIER_CDE); + hd64465_reg_write_1(HD64461_PCCCSCR(channel), 0); +} + +/* + * Card detect + */ +enum hd64465pcmcia_event_type +detect_card(int channel) +{ + u_int8_t r; + + r = hd64465_reg_read_1(HD64461_PCCISR(channel)) & + (HD64461_PCCISR_CD2 | HD64461_PCCISR_CD1); + + if (r == (HD64461_PCCISR_CD2 | HD64461_PCCISR_CD1)) { + DPRINTF("remove\n"); + return EVENT_REMOVE; + } + if (r == 0) { + DPRINTF("insert\n"); + return EVENT_INSERT; + } + DPRINTF("transition\n"); + + return (EVENT_NONE); +} + +/* + * Memory window access ops. + */ +void +hd64465pcmcia_memory_window16_switch(int channel, enum memory_window_16 window) +{ + bus_addr_t a = HD64461_PCCGCR(channel); + u_int8_t r; + + r = hd64465_reg_read_1(a); + r &= ~(HD64461_PCCGCR_PA25 | HD64461_PCCGCR_PA24); + + switch (window) { + case MEMWIN_16M_COMMON_0: + break; + case MEMWIN_16M_COMMON_1: + r |= HD64461_PCCGCR_PA24; + break; + case MEMWIN_16M_COMMON_2: + r |= HD64461_PCCGCR_PA25; + break; + case MEMWIN_16M_COMMON_3: + r |= (HD64461_PCCGCR_PA25 | HD64461_PCCGCR_PA24); + break; + } + + hd64465_reg_write_1(a, r); +} + +/* + * SH interface. + */ +void +__sh_set_bus_width(int channel, int width) +{ + u_int16_t r16; + + r16 = SHREG_BCR2; +#ifdef HD64465PCMCIA_DEBUG + dbg_bit_print_msg(r16, "BCR2"); +#endif + if (channel == 0) { + r16 &= ~((1 << 13)|(1 << 12)); + r16 |= 1 << (width == PCMCIA_WIDTH_IO8 ? 12 : 13); + } else { + r16 &= ~((1 << 11)|(1 << 10)); + r16 |= 1 << (width == PCMCIA_WIDTH_IO8 ? 10 : 11); + } + SHREG_BCR2 = r16; +} + +vaddr_t +__sh_hd64465_map_2page(paddr_t pa) +{ + static const u_int32_t mode[] = + { _PG_PCMCIA_ATTR16, _PG_PCMCIA_MEM16, _PG_PCMCIA_IO }; + vaddr_t va, v; + int i; + + /* allocate kernel virtual */ + v = va = uvm_km_valloc(kernel_map, 0x03000000); + if (va == NULL) { + PRINTF("can't allocate virtual for paddr 0x%08x\n", + (unsigned)pa); + + return (0); + } + + /* map to physical addreess with specified memory type. */ + for (i = 0; i < 3; i++, pa += 0x01000000, va += 0x01000000) { + if (__sh_hd64465_map(va, pa, 0x2000, mode[i]) != 0) { + uvm_km_free(kernel_map, v, 0x03000000); + return (0); + } + } + + return (v); +} + +int +__sh_hd64465_map(vaddr_t va, paddr_t pa, size_t sz, u_int32_t flags) +{ + pt_entry_t *pte; + paddr_t epa; + + KDASSERT(((pa & PAGE_MASK) == 0) && ((va & PAGE_MASK) == 0) && + ((sz & PAGE_MASK) == 0)); + + epa = pa + sz; + while (pa < epa) { + if (pmap_enter(pmap_kernel(), va, pa, + VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED) != 0) { + PRINTF("can't map va 0x%08x -> pa 0x%08x\n", + (unsigned)va, (unsigned)pa); + return (1); + } + + pte = kvtopte(va); + *pte &= ~PG_N; /* uncacheable */ + *pte |= flags; /* PTEA PCMCIA assistant bit */ + pmap_update_pg(va); + + pa += NBPG; + va += NBPG; + } + + pmap_update(pmap_kernel()); + + return (0); +} diff --git a/sys/arch/hpcsh/dev/hd64465/hd64465reg.h b/sys/arch/hpcsh/dev/hd64465/hd64465reg.h new file mode 100644 index 000000000000..062541666dcb --- /dev/null +++ b/sys/arch/hpcsh/dev/hd64465/hd64465reg.h @@ -0,0 +1,86 @@ +/* $NetBSD: hd64465reg.h,v 1.1 2002/02/11 17:27:16 uch Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * HD64465 power managerment and system configuration register. + */ +/* System Module Standby Register */ +#define HD64465_SMSCR 0xb0000000 +#define SMSCR_PS2ST 0x4000 +#define SMSCR_ADCST 0x1000 +#define SMSCR_UARTST 0x0800 +#define SMSCR_SCDIST 0x0200 +#define SMSCR_PPST 0x0100 +#define SMSCR_PC0ST 0x0040 +#define SMSCR_PC1ST 0x0020 +#define SMSCR_AFEST 0x0010 +#define SMSCR_TM0ST 0x0008 +#define SMSCR_TM1ST 0x0004 +#define SMSCR_IRDAST 0x0002 +#define SMSCR_KBCST 0x0001 + +/* System Configuration Register */ +#define HD64465_SCONFR 0xb0000002 +/* System Bus Control Register */ +#define HD64465_SBCR 0xb0000004 +/* System Peripheral Clock Control Register */ +#define HD64465_SPCCR 0xb0000006 +#define SPCCR_ADCCLK 0x8000 +#define SPCCR_UARTCLK 0x2000 +#define SPCCR_PPCLK 0x1000 +#define SPCCR_FIRCLK 0x0800 +#define SPCCR_SIRCLK 0x0400 +#define SPCCR_SCDICLK 0x0200 +#define SPCCR_KBCCLK 0x0100 +#define SPCCR_USBCLK 0x0080 +#define SPCCR_AFECLK 0x0040 +#define SPCCR_UCKOSC 0x0002 +#define SPCCR_AFEOSC 0x0001 + +/* System Peripheral S/W Reset Control Register */ +#define HD64465_SPSRCR 0xb0000008 +/* System PLL Control Register */ +#define HD64465_SPLLCR 0xb000000a +/* System Revision Register */ +#define HD64465_SRR 0xb000000c +/* System Test Mode Control Register */ +#define HD64465_STMCR 0xb000000e +/* System Device ID Register */ +#define HD64465_SDIDR 0xb0000010 /* ro 0x8122 */ +/* System Debug Port Control Register */ +#define HD64465_SDPCR 0xb0000ff0 diff --git a/sys/arch/hpcsh/dev/hd64465/hd64465uart.c b/sys/arch/hpcsh/dev/hd64465/hd64465uart.c new file mode 100644 index 000000000000..1c4b10a2d6f9 --- /dev/null +++ b/sys/arch/hpcsh/dev/hd64465/hd64465uart.c @@ -0,0 +1,196 @@ +/* $NetBSD: hd64465uart.c,v 1.1 2002/02/11 17:27:16 uch Exp $ */ + +/*- + * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opt_kgdb.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +STATIC struct hd64465uart_chip { + struct hpcsh_bus_space __tag_body; + bus_space_tag_t io_tag; + int console; +} hd64465uart_chip; + +struct hd64465uart_softc { + struct com_softc sc_com; + + struct hd64465uart_chip *sc_chip; + enum hd64465_module_id sc_module_id; +}; + +/* boot console */ +cdev_decl(com); +void comcnprobe(struct consdev *); +void comcninit(struct consdev *); + +STATIC int hd64465uart_match(struct device *, struct cfdata *, void *); +STATIC void hd64465uart_attach(struct device *, struct device *, void *); + +struct cfattach hd64465uart_ca = { + sizeof(struct hd64465uart_softc), hd64465uart_match, + hd64465uart_attach +}; + +STATIC void hd64465uart_init(void); +STATIC u_int8_t hd64465uart_read_1(void *, bus_space_handle_t, bus_size_t); +STATIC void hd64465uart_write_1(void *, bus_space_handle_t, bus_size_t, + u_int8_t); + +#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ +#ifndef COMCN_SPEED +#define COMCN_SPEED 19200 +#endif + +void +comcnprobe(struct consdev *cp) +{ + int maj; + + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == comopen) + break; + + /* Initialize required fields. */ + cp->cn_dev = makedev(maj, 0); + cp->cn_pri = CN_NORMAL; +} + +void +comcninit(struct consdev *cp) +{ + + hd64465uart_init(); + + comcnattach(hd64465uart_chip.io_tag, 0x0, COMCN_SPEED, COM_FREQ, + CONMODE); + + hd64465uart_chip.console = 1; +} + +int +hd64465uart_match(struct device *parent, struct cfdata *cf, void *aux) +{ + struct hd64465_attach_args *ha = aux; + + return (ha->ha_module_id == HD64465_MODULE_UART); +} + +void +hd64465uart_attach(struct device *parent, struct device *self, void *aux) +{ + struct hd64465_attach_args *ha = aux; + struct hd64465uart_softc *sc = (struct hd64465uart_softc *)self; + struct com_softc *csc = &sc->sc_com; + + sc->sc_chip = &hd64465uart_chip; + + sc->sc_module_id = ha->ha_module_id; + + hd64465uart_init(); + + csc->sc_iot = sc->sc_chip->io_tag; + bus_space_map(csc->sc_iot, 0, 8, 0, &csc->sc_ioh); + csc->sc_iobase = 0; + csc->sc_frequency = COM_FREQ; + + /* supply clock XXX notyet */ + + /* sanity check */ + if (!comprobe1(csc->sc_iot, csc->sc_ioh)) { + printf(": device problem. don't attach.\n"); + + /* stop clock XXX notyet */ + return; + } + + com_attach_subr(csc); + + /* register interrupt handler */ + hd64465_intr_establish(HD64465_IRQ_UART, IST_EDGE, IPL_TTY, + comintr, self); +} + +void +hd64465uart_init() +{ + + if (hd64465uart_chip.io_tag) + return; + + hd64465uart_chip.io_tag = bus_space_create( + &hd64465uart_chip.__tag_body, "HD64465 UART I/O", + 0xb0008000, 0); /* no extent */ + + /* override bus_space_read_1, bus_space_write_1 */ + hd64465uart_chip.io_tag->hbs_r_1 = hd64465uart_read_1; + hd64465uart_chip.io_tag->hbs_w_1 = hd64465uart_write_1; +} + +u_int8_t +hd64465uart_read_1(void *t, bus_space_handle_t h, bus_size_t ofs) +{ + + return *(__volatile__ u_int8_t *)(h + (ofs << 1)); +} + +void +hd64465uart_write_1(void *t, bus_space_handle_t h, bus_size_t ofs, + u_int8_t val) +{ + + *(__volatile__ u_int8_t *)(h + (ofs << 1)) = val; +} diff --git a/sys/arch/hpcsh/dev/hd64465/hd64465uartvar.h b/sys/arch/hpcsh/dev/hd64465/hd64465uartvar.h new file mode 100644 index 000000000000..12098e2392c9 --- /dev/null +++ b/sys/arch/hpcsh/dev/hd64465/hd64465uartvar.h @@ -0,0 +1,60 @@ +/* $NetBSD: hd64465uartvar.h,v 1.1 2002/02/11 17:27:16 uch Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define HD64465COM_TX_BUSY() \ + while ((VOLATILE_REF8(HD64465_ULSR_REG8) & LSR_TXRDY) == 0) + +#define HD64465COM_PUTC(c) \ +do { \ + HD64465COM_TX_BUSY(); \ + VOLATILE_REF8(HD64465_UTBR_REG8) = (c); \ + HD64465COM_TX_BUSY(); \ +} while (/*CONSTCOND*/0) + +#define HD64465COM_PRINT(s) \ +do { \ + char *__s =(char *)(s); \ + int __i; \ + for (__i = 0; __s[__i] != '\0'; __i++) { \ + char __c = __s[__i]; \ + if (__c == '\n') \ + HD64465COM_PUTC('\r'); \ + HD64465COM_PUTC(__c); \ + } \ +} while (/*CONSTCOND*/0) + diff --git a/sys/arch/hpcsh/dev/hd64465/hd64465var.h b/sys/arch/hpcsh/dev/hd64465/hd64465var.h new file mode 100644 index 000000000000..67a6a44cc54e --- /dev/null +++ b/sys/arch/hpcsh/dev/hd64465/hd64465var.h @@ -0,0 +1,95 @@ +/* $NetBSD: hd64465var.h,v 1.1 2002/02/11 17:27:16 uch Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * HD64465 register access macro. + */ +#define hd64465_reg_read_1(r) (*((volatile u_int8_t *)(r))) +#define hd64465_reg_write_1(r, v) (*((volatile u_int8_t *)(r)) = (v)) +#define hd64465_reg_read_2(r) (*((volatile u_int16_t *)(r))) +#define hd64465_reg_write_2(r, v) (*((volatile u_int16_t *)(r)) = (v)) + +/* + * HD64465 modules canonical ID. + */ +enum hd64465_module_id { + HD64465_MODULE_INTERFACE = 0, + HD64465_MODULE_INTC, + HD64465_MODULE_PS2IF, + HD64465_MODULE_PCMCIA, + HD64465_MODULE_AFE, + HD64465_MODULE_GPIO, + HD64465_MODULE_TIMER, + HD64465_MODULE_KBC, + HD64465_MODULE_IRDA, + HD64465_MODULE_UART, + HD64465_MODULE_PARALEL, + HD64465_MODULE_CODEC, + HD64465_MODULE_OHCI, + HD64465_MODULE_ADC +}; + +struct hd64465_attach_args { + enum hd64465_module_id ha_module_id; +}; + +enum hd64465_irq { + HD64465_IRQ_PS2KB = 0, + HD64465_IRQ_PCC0, + HD64465_IRQ_PCC1, + HD64465_IRQ_AFE, + HD64465_IRQ_GPIO, + HD64465_IRQ_TMU0, + HD64465_IRQ_TMU1, + HD64465_IRQ_KBC, + HD64465_IRQ_PS2MS, + HD64465_IRQ_IRDA, + HD64465_IRQ_UART, + HD64465_IRQ_PPR, + HD64465_IRQ_SCDI, + HD64465_IRQ_OHCI, + HD64465_IRQ_ADC, +}; + +void hd64465_intr_disable(void); +void hd64465_intr_mask(void); +void hd64465_intr_unmask(void); +void hd64465_intr_reboot(void); +void *hd64465_intr_establish(enum hd64465_irq, int, int, int (*)(void *), + void *); +void hd64465_intr_disestablish(void *);