1/*	$NetBSD: kobo_usb.c,v 1.4 2024/02/22 23:16:10 andvar Exp $	*/
2
3/*
4 * Copyright (c) 2012  Genetec Corporation.  All rights reserved.
5 * Written by Hiroyuki Bessho for Genetec Corporation.
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 GENETEC CORPORATION ``AS IS'' AND
17 * 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 GENETEC CORPORATION
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__KERNEL_RCSID(0, "$NetBSD: kobo_usb.c,v 1.4 2024/02/22 23:16:10 andvar Exp $");
31
32#include "opt_imx.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/conf.h>
37#include <sys/kernel.h>
38#include <sys/kthread.h>
39#include <sys/device.h>
40#include <sys/intr.h>
41#include <sys/bus.h>
42
43#include <dev/usb/usb.h>
44#include <dev/usb/usbdi.h>
45#include <dev/usb/usbdivar.h>
46#include <dev/usb/usb_mem.h>
47
48#include <dev/usb/ehcireg.h>
49#include <dev/usb/ehcivar.h>
50
51#include <arm/imx/imx51reg.h>
52#include <arm/imx/imx51var.h>
53#include <arm/imx/imxusbreg.h>
54#include <arm/imx/imxusbvar.h>
55#include <arm/imx/imx50_iomuxreg.h>
56#include <arm/imx/imx51_ccmreg.h>
57#include <arm/imx/imx51_ccmvar.h>
58
59#include "locators.h"
60
61struct kobo_usbc_softc {
62	struct imxusbc_softc sc_imxusbc; /* Must be first */
63};
64
65static int	imxusbc_match(device_t, cfdata_t, void *);
66static void	imxusbc_attach(device_t, device_t, void *);
67static void	kobo_usb_init(struct imxehci_softc *, uintptr_t);
68
69static void	init_otg(struct imxehci_softc *);
70static void	init_h1(struct imxehci_softc *);
71
72extern const struct iomux_conf iomux_usb1_config[];
73
74/* attach structures */
75CFATTACH_DECL_NEW(imxusbc_axi, sizeof(struct kobo_usbc_softc),
76    imxusbc_match, imxusbc_attach, NULL, NULL);
77
78static int
79imxusbc_match(device_t parent, cfdata_t cf, void *aux)
80{
81	struct axi_attach_args *aa = aux;
82
83	if (aa->aa_addr == USBOH3_BASE)
84		return 1;
85	return 0;
86}
87
88static void
89imxusbc_attach(device_t parent, device_t self, void *aux)
90{
91	struct imxusbc_softc *sc = device_private(self);
92	struct axi_attach_args *aa = aux;
93
94	aprint_normal("\n");
95	aprint_normal(": Universal Serial Bus Controller\n");
96
97	if (aa->aa_size == AXICF_SIZE_DEFAULT)
98		aa->aa_size = USBOH3_SIZE;
99
100	sc->sc_init_md_hook = kobo_usb_init;
101	sc->sc_intr_establish_md_hook = NULL;
102	sc->sc_setup_md_hook = NULL;
103
104	imxusbc_attach_common(parent, self, aa->aa_iot, aa->aa_addr, aa->aa_size);
105}
106
107static void
108kobo_usb_init(struct imxehci_softc *sc, uintptr_t data)
109{
110	switch (sc->sc_unit) {
111	case 0:	/* OTG controller */
112		init_otg(sc);
113		break;
114	case 1:	/* EHCI Host 1 */
115		init_h1(sc);
116		break;
117	default:
118		aprint_error_dev(sc->sc_hsc.sc_dev, "unit %d not supported\n",
119		    sc->sc_unit);
120	}
121}
122
123static void
124init_otg(struct imxehci_softc *sc)
125{
126	struct imxusbc_softc *usbc = sc->sc_usbc;
127	uint32_t reg;
128
129	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USB_CLKONOFF_CTRL);
130	reg &= ~USB_CLKONOFF_CTRL_OTG_AHBCLK_OFF;
131	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USB_CLKONOFF_CTRL, reg);
132
133	sc->sc_iftype = IMXUSBC_IF_UTMI_WIDE;
134
135	imxehci_reset(sc);
136
137	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0);
138	reg |= PHYCTRL0_OTG_OVER_CUR_DIS | PHYCTRL0_SUSPENDM;
139	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0, reg);
140
141	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USBCTRL);
142	reg &= ~USBCTRL_OWIR;
143	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USBCTRL, reg);
144
145	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL1);
146	reg = (reg & ~PHYCTRL1_PLLDIVVALUE_MASK) | PHYCTRL1_PLLDIVVALUE_24MHZ;
147	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL1, reg);
148}
149
150static void
151init_h1(struct imxehci_softc *sc)
152{
153	struct imxusbc_softc *usbc = sc->sc_usbc;
154	uint32_t reg;
155
156	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USB_CLKONOFF_CTRL);
157	reg &= ~USB_CLKONOFF_CTRL_H1_AHBCLK_OFF;
158	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_USB_CLKONOFF_CTRL, reg);
159
160	imxehci_reset(sc);
161
162	/* select INTERNAL PHY interface for Host 1 */
163	sc->sc_iftype = IMXUSBC_IF_UTMI;
164
165	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh,
166	    USBOH3_USBCTRL);
167	reg |= USBCTRL_H1PM;
168	reg &= ~(USBCTRL_H1WIE);
169	reg &= ~(USBCTRL_H1UIE);
170	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh,
171	    USBOH3_USBCTRL, reg);
172
173	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_PHYCTRL0);
174	reg &= ~PHYCTRL0_H1_OVER_CUR_DIS;
175	reg |= PHYCTRL0_H1_OVER_CUR_POL;
176	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh,USBOH3_PHYCTRL0 , reg);
177
178	delay(1000);
179
180	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_UH1_PHY_CTRL_1);
181	reg &= ~PHYCTRL1_PLLDIVVALUE_MASK;
182	reg |= PHYCTRL1_PLLDIVVALUE_24MHZ;
183	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_UH1_PHY_CTRL_1, reg);
184
185	reg = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_UH1_PHY_CTRL_0);
186	reg &= ~PHYCTRL0_CHGRDETON;
187	reg &= ~PHYCTRL0_CHGRDETEN;
188	bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBOH3_UH1_PHY_CTRL_0, reg);
189}
190
191
192