[BACK]Return to dw_apb_uart.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / fdt

Annotation of src/sys/dev/fdt/dw_apb_uart.c, Revision 1.11

1.11    ! jmcneill    1: /* $NetBSD: dw_apb_uart.c,v 1.10 2021/01/27 03:10:21 thorpej Exp $ */
1.1       jmcneill    2:
                      3: /*-
                      4:  * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     17:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     18:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     19:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     20:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     21:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     22:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     23:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     24:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     25:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     26:  * POSSIBILITY OF SUCH DAMAGE.
                     27:  */
                     28:
                     29: #include <sys/cdefs.h>
                     30:
1.11    ! jmcneill   31: __KERNEL_RCSID(1, "$NetBSD: dw_apb_uart.c,v 1.10 2021/01/27 03:10:21 thorpej Exp $");
1.1       jmcneill   32:
                     33: #include <sys/param.h>
                     34: #include <sys/bus.h>
                     35: #include <sys/device.h>
                     36: #include <sys/intr.h>
                     37: #include <sys/systm.h>
                     38: #include <sys/time.h>
                     39: #include <sys/termios.h>
                     40:
                     41: #include <dev/ic/comvar.h>
                     42:
                     43: #include <dev/fdt/fdtvar.h>
                     44:
                     45: static int dw_apb_uart_match(device_t, cfdata_t, void *);
                     46: static void dw_apb_uart_attach(device_t, device_t, void *);
                     47:
1.10      thorpej    48: static const struct device_compatible_entry compat_data[] = {
                     49:        { .compat = "snps,dw-apb-uart" },
                     50:        DEVICE_COMPAT_EOL
1.1       jmcneill   51: };
                     52:
                     53: struct dw_apb_uart_softc {
                     54:        struct com_softc ssc_sc;
                     55:        void *ssc_ih;
                     56:
                     57:        struct clk *ssc_clk;
1.2       jmcneill   58:        struct clk *ssc_pclk;
1.1       jmcneill   59:        struct fdtbus_reset *ssc_rst;
                     60: };
                     61:
                     62: CFATTACH_DECL_NEW(dw_apb_uart, sizeof(struct dw_apb_uart_softc),
                     63:        dw_apb_uart_match, dw_apb_uart_attach, NULL, NULL);
                     64:
                     65: static int
                     66: dw_apb_uart_match(device_t parent, cfdata_t cf, void *aux)
                     67: {
                     68:        struct fdt_attach_args * const faa = aux;
                     69:
1.10      thorpej    70:        return of_compatible_match(faa->faa_phandle, compat_data);
1.1       jmcneill   71: }
                     72:
                     73: static void
                     74: dw_apb_uart_attach(device_t parent, device_t self, void *aux)
                     75: {
                     76:        struct dw_apb_uart_softc * const ssc = device_private(self);
                     77:        struct com_softc * const sc = &ssc->ssc_sc;
                     78:        struct fdt_attach_args * const faa = aux;
1.11    ! jmcneill   79:        const int phandle = faa->faa_phandle;
1.6       jmcneill   80:        bus_space_tag_t bst = faa->faa_bst;
1.1       jmcneill   81:        bus_space_handle_t bsh;
                     82:        char intrstr[128];
                     83:        bus_addr_t addr;
                     84:        bus_size_t size;
1.11    ! jmcneill   85:        u_int reg_shift, reg_iowidth;
1.1       jmcneill   86:        int error;
                     87:
1.11    ! jmcneill   88:        if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
1.1       jmcneill   89:                aprint_error(": couldn't get registers\n");
                     90:                return;
                     91:        }
                     92:
1.11    ! jmcneill   93:        if (of_getprop_uint32(phandle, "reg-shift", &reg_shift)) {
1.1       jmcneill   94:                /* missing or bad reg-shift property, assume 2 */
1.6       jmcneill   95:                reg_shift = 2;
1.1       jmcneill   96:        }
1.11    ! jmcneill   97:        if (of_getprop_uint32(phandle, "reg-io-width", &reg_iowidth)) {
        !            98:                /* missing or bad reg-io-width propery, assume 1 */
        !            99:                reg_iowidth = 1;
        !           100:        }
1.1       jmcneill  101:
                    102:        sc->sc_dev = self;
                    103:
1.11    ! jmcneill  104:        ssc->ssc_clk = fdtbus_clock_get_index(phandle, 0);
1.1       jmcneill  105:        if (ssc->ssc_clk == NULL) {
                    106:                aprint_error(": couldn't get clock\n");
                    107:                return;
                    108:        }
                    109:        if (clk_enable(ssc->ssc_clk) != 0) {
                    110:                aprint_error(": couldn't enable clock\n");
                    111:                return;
                    112:        }
                    113:
1.11    ! jmcneill  114:        ssc->ssc_pclk = fdtbus_clock_get(phandle, "apb_pclk");
1.2       jmcneill  115:        if (ssc->ssc_pclk != NULL && clk_enable(ssc->ssc_pclk) != 0) {
                    116:                aprint_error(": couldn't enable peripheral clock\n");
                    117:                return;
                    118:        }
                    119:
1.11    ! jmcneill  120:        ssc->ssc_rst = fdtbus_reset_get_index(phandle, 0);
1.1       jmcneill  121:        if (ssc->ssc_rst && fdtbus_reset_deassert(ssc->ssc_rst) != 0) {
                    122:                aprint_error(": couldn't de-assert reset\n");
                    123:                return;
                    124:        }
                    125:
                    126:        sc->sc_frequency = clk_get_rate(ssc->ssc_clk);
                    127:        sc->sc_type = COM_TYPE_DW_APB;
                    128:
                    129:        error = bus_space_map(bst, addr, size, 0, &bsh);
                    130:        if (error) {
1.3       christos  131:                aprint_error(": couldn't map %#" PRIx64 ": %d", (uint64_t)addr, error);
1.1       jmcneill  132:                return;
                    133:        }
                    134:
1.11    ! jmcneill  135:        com_init_regs_stride_width(&sc->sc_regs, bst, bsh, addr, reg_shift, reg_iowidth);
1.1       jmcneill  136:
                    137:        com_attach_subr(sc);
                    138:
1.11    ! jmcneill  139:        if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
1.1       jmcneill  140:                aprint_error_dev(self, "failed to decode interrupt\n");
                    141:                return;
                    142:        }
                    143:
1.11    ! jmcneill  144:        ssc->ssc_ih = fdtbus_intr_establish_xname(phandle, 0,
1.9       ryo       145:            IPL_SERIAL, FDT_INTR_MPSAFE, comintr, sc, device_xname(self));
1.1       jmcneill  146:        if (ssc->ssc_ih == NULL) {
                    147:                aprint_error_dev(self, "failed to establish interrupt on %s\n",
                    148:                    intrstr);
                    149:        }
                    150:        aprint_normal_dev(self, "interrupting on %s\n", intrstr);
                    151: }
                    152:
                    153: /*
                    154:  * Console support
                    155:  */
                    156:
                    157: static int
                    158: dw_apb_uart_console_match(int phandle)
                    159: {
1.10      thorpej   160:        return of_compatible_match(phandle, compat_data);
1.1       jmcneill  161: }
                    162:
                    163: static void
                    164: dw_apb_uart_console_consinit(struct fdt_attach_args *faa, u_int uart_freq)
                    165: {
                    166:        const int phandle = faa->faa_phandle;
1.6       jmcneill  167:        bus_space_tag_t bst = faa->faa_bst;
                    168:        bus_space_handle_t dummy_bsh;
                    169:        struct com_regs regs;
1.1       jmcneill  170:        bus_addr_t addr;
                    171:        tcflag_t flags;
1.11    ! jmcneill  172:        u_int reg_shift, reg_iowidth;
1.1       jmcneill  173:        int speed;
                    174:
                    175:        fdtbus_get_reg(phandle, 0, &addr, NULL);
                    176:        speed = fdtbus_get_stdout_speed();
                    177:        if (speed < 0)
                    178:                speed = 115200; /* default */
                    179:        flags = fdtbus_get_stdout_flags();
                    180:
1.6       jmcneill  181:        if (of_getprop_uint32(phandle, "reg-shift", &reg_shift)) {
1.7       jmcneill  182:                /* missing or bad reg-shift property, assume 2 */
                    183:                reg_shift = 2;
1.6       jmcneill  184:        }
1.11    ! jmcneill  185:        if (of_getprop_uint32(phandle, "reg-io-width", &reg_iowidth)) {
        !           186:                /* missing or bad reg-io-width propery, assume 1 */
        !           187:                reg_iowidth = 1;
        !           188:        }
1.6       jmcneill  189:
                    190:        memset(&dummy_bsh, 0, sizeof(dummy_bsh));
1.11    ! jmcneill  191:        com_init_regs_stride_width(&regs, bst, dummy_bsh, addr, reg_shift, reg_iowidth);
1.6       jmcneill  192:
                    193:        if (comcnattach1(&regs, speed, uart_freq, COM_TYPE_DW_APB, flags))
1.1       jmcneill  194:                panic("Cannot initialize dw-apb-uart console");
                    195: }
                    196:
                    197: static const struct fdt_console dw_apb_uart_console = {
                    198:        .match = dw_apb_uart_console_match,
                    199:        .consinit = dw_apb_uart_console_consinit,
                    200: };
                    201:
                    202: FDT_CONSOLE(dw_apb_uart, &dw_apb_uart_console);

CVSweb <webmaster@jp.NetBSD.org>