Use DEVICE_COMPAT_EOL.diff -r1.8 -r1.9 src/sys/arch/arm/rockchip/rk3399_iomux.c
(thorpej)
--- src/sys/arch/arm/rockchip/rk3399_iomux.c 2021/01/25 14:20:38 1.8
+++ src/sys/arch/arm/rockchip/rk3399_iomux.c 2021/01/27 02:00:02 1.9
@@ -1,527 +1,527 @@ | @@ -1,527 +1,527 @@ | |||
1 | /* $NetBSD: rk3399_iomux.c,v 1.8 2021/01/25 14:20:38 thorpej Exp $ */ | 1 | /* $NetBSD: rk3399_iomux.c,v 1.9 2021/01/27 02:00:02 thorpej Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | 4 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | //#define RK3399_IOMUX_DEBUG | 29 | //#define RK3399_IOMUX_DEBUG | |
30 | 30 | |||
31 | #include <sys/cdefs.h> | 31 | #include <sys/cdefs.h> | |
32 | __KERNEL_RCSID(0, "$NetBSD: rk3399_iomux.c,v 1.8 2021/01/25 14:20:38 thorpej Exp $"); | 32 | __KERNEL_RCSID(0, "$NetBSD: rk3399_iomux.c,v 1.9 2021/01/27 02:00:02 thorpej Exp $"); | |
33 | 33 | |||
34 | #include <sys/param.h> | 34 | #include <sys/param.h> | |
35 | #include <sys/bus.h> | 35 | #include <sys/bus.h> | |
36 | #include <sys/device.h> | 36 | #include <sys/device.h> | |
37 | #include <sys/intr.h> | 37 | #include <sys/intr.h> | |
38 | #include <sys/systm.h> | 38 | #include <sys/systm.h> | |
39 | #include <sys/mutex.h> | 39 | #include <sys/mutex.h> | |
40 | #include <sys/kmem.h> | 40 | #include <sys/kmem.h> | |
41 | #include <sys/gpio.h> | 41 | #include <sys/gpio.h> | |
42 | #include <sys/lwp.h> | 42 | #include <sys/lwp.h> | |
43 | 43 | |||
44 | #include <dev/fdt/fdtvar.h> | 44 | #include <dev/fdt/fdtvar.h> | |
45 | #include <dev/fdt/syscon.h> | 45 | #include <dev/fdt/syscon.h> | |
46 | 46 | |||
47 | /* PU/PD control */ | 47 | /* PU/PD control */ | |
48 | #define GRF_GPIO_P_CTL(_idx) (0x3 << (((_idx) & 7) * 2)) | 48 | #define GRF_GPIO_P_CTL(_idx) (0x3 << (((_idx) & 7) * 2)) | |
49 | #define GRF_GPIO_P_WRITE_EN(_idx) (0x3 << (((_idx) & 7) * 2 + 16)) | 49 | #define GRF_GPIO_P_WRITE_EN(_idx) (0x3 << (((_idx) & 7) * 2 + 16)) | |
50 | /* Different bias value mapping based on pull type of pin */ | 50 | /* Different bias value mapping based on pull type of pin */ | |
51 | #define IO_DEF_GPIO_P_CTL_Z 0 | 51 | #define IO_DEF_GPIO_P_CTL_Z 0 | |
52 | #define IO_DEF_GPIO_P_CTL_PULLUP 1 | 52 | #define IO_DEF_GPIO_P_CTL_PULLUP 1 | |
53 | #define IO_DEF_GPIO_P_CTL_PULLDOWN 2 | 53 | #define IO_DEF_GPIO_P_CTL_PULLDOWN 2 | |
54 | #define IO_DEF_GPIO_P_CTL_RESERVED 3 | 54 | #define IO_DEF_GPIO_P_CTL_RESERVED 3 | |
55 | #define IO_1V8_GPIO_P_CTL_Z 0 | 55 | #define IO_1V8_GPIO_P_CTL_Z 0 | |
56 | #define IO_1V8_GPIO_P_CTL_PULLDOWN 1 | 56 | #define IO_1V8_GPIO_P_CTL_PULLDOWN 1 | |
57 | #define IO_1V8_GPIO_P_CTL_Z_ALT 2 | 57 | #define IO_1V8_GPIO_P_CTL_Z_ALT 2 | |
58 | #define IO_1V8_GPIO_P_CTL_PULLUP 3 | 58 | #define IO_1V8_GPIO_P_CTL_PULLUP 3 | |
59 | 59 | |||
60 | /* Drive strength control */ | 60 | /* Drive strength control */ | |
61 | /* Different drive strength value mapping for GRF and PMU registers */ | 61 | /* Different drive strength value mapping for GRF and PMU registers */ | |
62 | #define GRF_GPIO_E_CTL_2MA 0 | 62 | #define GRF_GPIO_E_CTL_2MA 0 | |
63 | #define GRF_GPIO_E_CTL_4MA 1 | 63 | #define GRF_GPIO_E_CTL_4MA 1 | |
64 | #define GRF_GPIO_E_CTL_8MA 2 | 64 | #define GRF_GPIO_E_CTL_8MA 2 | |
65 | #define GRF_GPIO_E_CTL_12MA 3 | 65 | #define GRF_GPIO_E_CTL_12MA 3 | |
66 | #define PMU_GPIO_E_CTL_5MA 0 | 66 | #define PMU_GPIO_E_CTL_5MA 0 | |
67 | #define PMU_GPIO_E_CTL_10MA 1 | 67 | #define PMU_GPIO_E_CTL_10MA 1 | |
68 | #define PMU_GPIO_E_CTL_15MA 2 | 68 | #define PMU_GPIO_E_CTL_15MA 2 | |
69 | #define PMU_GPIO_E_CTL_20MA 3 | 69 | #define PMU_GPIO_E_CTL_20MA 3 | |
70 | 70 | |||
71 | enum rk3399_drv_type { | 71 | enum rk3399_drv_type { | |
72 | RK3399_DRV_TYPE_IO_DEFAULT, | 72 | RK3399_DRV_TYPE_IO_DEFAULT, | |
73 | RK3399_DRV_TYPE_IO_1V8_3V0, | 73 | RK3399_DRV_TYPE_IO_1V8_3V0, | |
74 | RK3399_DRV_TYPE_IO_1V8, | 74 | RK3399_DRV_TYPE_IO_1V8, | |
75 | RK3399_DRV_TYPE_IO_1V8_3V0_AUTO, | 75 | RK3399_DRV_TYPE_IO_1V8_3V0_AUTO, | |
76 | RK3399_DRV_TYPE_IO_3V3, | 76 | RK3399_DRV_TYPE_IO_3V3, | |
77 | }; | 77 | }; | |
78 | 78 | |||
79 | static int rk3399_drv_strength[5][9] = { | 79 | static int rk3399_drv_strength[5][9] = { | |
80 | [RK3399_DRV_TYPE_IO_DEFAULT] = { 2, 4, 8, 12, -1 }, | 80 | [RK3399_DRV_TYPE_IO_DEFAULT] = { 2, 4, 8, 12, -1 }, | |
81 | [RK3399_DRV_TYPE_IO_1V8_3V0] = { 3, 6, 9, 12, -1 }, | 81 | [RK3399_DRV_TYPE_IO_1V8_3V0] = { 3, 6, 9, 12, -1 }, | |
82 | [RK3399_DRV_TYPE_IO_1V8] = { 5, 10, 15, 20, -1 }, | 82 | [RK3399_DRV_TYPE_IO_1V8] = { 5, 10, 15, 20, -1 }, | |
83 | [RK3399_DRV_TYPE_IO_1V8_3V0_AUTO] = { 4, 6, 8, 10, 12, 14, 16, 18, -1 }, | 83 | [RK3399_DRV_TYPE_IO_1V8_3V0_AUTO] = { 4, 6, 8, 10, 12, 14, 16, 18, -1 }, | |
84 | [RK3399_DRV_TYPE_IO_3V3] = { 4, 7, 10, 13, 16, 19, 22, 26, -1 }, | 84 | [RK3399_DRV_TYPE_IO_3V3] = { 4, 7, 10, 13, 16, 19, 22, 26, -1 }, | |
85 | }; | 85 | }; | |
86 | 86 | |||
87 | enum rk3399_pull_type { | 87 | enum rk3399_pull_type { | |
88 | RK3399_PULL_TYPE_IO_DEFAULT, | 88 | RK3399_PULL_TYPE_IO_DEFAULT, | |
89 | RK3399_PULL_TYPE_IO_1V8_ONLY, | 89 | RK3399_PULL_TYPE_IO_1V8_ONLY, | |
90 | }; | 90 | }; | |
91 | 91 | |||
92 | struct rk3399_iomux { | 92 | struct rk3399_iomux { | |
93 | enum rk3399_drv_type drv_type; | 93 | enum rk3399_drv_type drv_type; | |
94 | enum rk3399_pull_type pull_type; | 94 | enum rk3399_pull_type pull_type; | |
95 | }; | 95 | }; | |
96 | 96 | |||
97 | struct rk3399_iomux_bank { | 97 | struct rk3399_iomux_bank { | |
98 | struct rk3399_iomux iomux[5]; | 98 | struct rk3399_iomux iomux[5]; | |
99 | u_int regs; | 99 | u_int regs; | |
100 | #define RK_IOMUX_REGS_GRF 0 | 100 | #define RK_IOMUX_REGS_GRF 0 | |
101 | #define RK_IOMUX_REGS_PMU 1 | 101 | #define RK_IOMUX_REGS_PMU 1 | |
102 | }; | 102 | }; | |
103 | 103 | |||
104 | static const struct rk3399_iomux_bank rk3399_iomux_banks[] = { | 104 | static const struct rk3399_iomux_bank rk3399_iomux_banks[] = { | |
105 | [0] = { | 105 | [0] = { | |
106 | .regs = RK_IOMUX_REGS_PMU, | 106 | .regs = RK_IOMUX_REGS_PMU, | |
107 | .iomux = { | 107 | .iomux = { | |
108 | [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8, | 108 | [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8, | |
109 | .pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY }, | 109 | .pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY }, | |
110 | [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8, | 110 | [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8, | |
111 | .pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY }, | 111 | .pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY }, | |
112 | [2] = { .drv_type = RK3399_DRV_TYPE_IO_DEFAULT, | 112 | [2] = { .drv_type = RK3399_DRV_TYPE_IO_DEFAULT, | |
113 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 113 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
114 | [3] = { .drv_type = RK3399_DRV_TYPE_IO_DEFAULT, | 114 | [3] = { .drv_type = RK3399_DRV_TYPE_IO_DEFAULT, | |
115 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 115 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
116 | }, | 116 | }, | |
117 | }, | 117 | }, | |
118 | [1] = { | 118 | [1] = { | |
119 | .regs = RK_IOMUX_REGS_PMU, | 119 | .regs = RK_IOMUX_REGS_PMU, | |
120 | .iomux = { | 120 | .iomux = { | |
121 | [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | 121 | [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | |
122 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 122 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
123 | [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | 123 | [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | |
124 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 124 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
125 | [2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | 125 | [2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | |
126 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 126 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
127 | [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | 127 | [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | |
128 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 128 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
129 | } | 129 | } | |
130 | }, | 130 | }, | |
131 | [2] = { | 131 | [2] = { | |
132 | .regs = RK_IOMUX_REGS_GRF, | 132 | .regs = RK_IOMUX_REGS_GRF, | |
133 | .iomux = { | 133 | .iomux = { | |
134 | [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | 134 | [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | |
135 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 135 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
136 | [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | 136 | [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | |
137 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 137 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
138 | [2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8, | 138 | [2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8, | |
139 | .pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY }, | 139 | .pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY }, | |
140 | [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8, | 140 | [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8, | |
141 | .pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY }, | 141 | .pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY }, | |
142 | }, | 142 | }, | |
143 | }, | 143 | }, | |
144 | [3] = { | 144 | [3] = { | |
145 | .regs = RK_IOMUX_REGS_GRF, | 145 | .regs = RK_IOMUX_REGS_GRF, | |
146 | .iomux = { | 146 | .iomux = { | |
147 | [0] = { .drv_type = RK3399_DRV_TYPE_IO_3V3, | 147 | [0] = { .drv_type = RK3399_DRV_TYPE_IO_3V3, | |
148 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 148 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
149 | [1] = { .drv_type = RK3399_DRV_TYPE_IO_3V3, | 149 | [1] = { .drv_type = RK3399_DRV_TYPE_IO_3V3, | |
150 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 150 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
151 | [2] = { .drv_type = RK3399_DRV_TYPE_IO_3V3, | 151 | [2] = { .drv_type = RK3399_DRV_TYPE_IO_3V3, | |
152 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 152 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
153 | [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | 153 | [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | |
154 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 154 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
155 | }, | 155 | }, | |
156 | }, | 156 | }, | |
157 | [4] = { | 157 | [4] = { | |
158 | .regs = RK_IOMUX_REGS_GRF, | 158 | .regs = RK_IOMUX_REGS_GRF, | |
159 | .iomux = { | 159 | .iomux = { | |
160 | [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | 160 | [0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | |
161 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 161 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
162 | [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0_AUTO, | 162 | [1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0_AUTO, | |
163 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 163 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
164 | [2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | 164 | [2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | |
165 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 165 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
166 | [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | 166 | [3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0, | |
167 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | 167 | .pull_type = RK3399_PULL_TYPE_IO_DEFAULT }, | |
168 | }, | 168 | }, | |
169 | }, | 169 | }, | |
170 | }; | 170 | }; | |
171 | 171 | |||
172 | #define RK3399_IOMUX_BANK_IS_PMU(_bank) (rk3399_iomux_banks[(_bank)].regs == RK_IOMUX_REGS_PMU) | 172 | #define RK3399_IOMUX_BANK_IS_PMU(_bank) (rk3399_iomux_banks[(_bank)].regs == RK_IOMUX_REGS_PMU) | |
173 | 173 | |||
174 | struct rk3399_iomux_conf { | 174 | struct rk3399_iomux_conf { | |
175 | const struct rk3399_iomux_bank *banks; | 175 | const struct rk3399_iomux_bank *banks; | |
176 | u_int nbanks; | 176 | u_int nbanks; | |
177 | }; | 177 | }; | |
178 | 178 | |||
179 | static const struct rk3399_iomux_conf rk3399_iomux_conf = { | 179 | static const struct rk3399_iomux_conf rk3399_iomux_conf = { | |
180 | .banks = rk3399_iomux_banks, | 180 | .banks = rk3399_iomux_banks, | |
181 | .nbanks = __arraycount(rk3399_iomux_banks), | 181 | .nbanks = __arraycount(rk3399_iomux_banks), | |
182 | }; | 182 | }; | |
183 | 183 | |||
184 | static const struct device_compatible_entry compat_data[] = { | 184 | static const struct device_compatible_entry compat_data[] = { | |
185 | { .compat = "rockchip,rk3399-pinctrl", .data = &rk3399_iomux_conf }, | 185 | { .compat = "rockchip,rk3399-pinctrl", .data = &rk3399_iomux_conf }, | |
186 | { } | 186 | DEVICE_COMPAT_EOL | |
187 | }; | 187 | }; | |
188 | 188 | |||
189 | struct rk3399_iomux_softc { | 189 | struct rk3399_iomux_softc { | |
190 | device_t sc_dev; | 190 | device_t sc_dev; | |
191 | struct syscon *sc_syscon[2]; | 191 | struct syscon *sc_syscon[2]; | |
192 | 192 | |||
193 | const struct rk3399_iomux_conf *sc_conf; | 193 | const struct rk3399_iomux_conf *sc_conf; | |
194 | }; | 194 | }; | |
195 | 195 | |||
196 | #define LOCK(syscon) \ | 196 | #define LOCK(syscon) \ | |
197 | syscon_lock(syscon) | 197 | syscon_lock(syscon) | |
198 | #define UNLOCK(syscon) \ | 198 | #define UNLOCK(syscon) \ | |
199 | syscon_unlock(syscon) | 199 | syscon_unlock(syscon) | |
200 | #define RD4(syscon, reg) \ | 200 | #define RD4(syscon, reg) \ | |
201 | syscon_read_4(syscon, (reg)) | 201 | syscon_read_4(syscon, (reg)) | |
202 | #define WR4(syscon, reg, val) \ | 202 | #define WR4(syscon, reg, val) \ | |
203 | syscon_write_4(syscon, (reg), (val)) | 203 | syscon_write_4(syscon, (reg), (val)) | |
204 | 204 | |||
205 | static int rk3399_iomux_match(device_t, cfdata_t, void *); | 205 | static int rk3399_iomux_match(device_t, cfdata_t, void *); | |
206 | static void rk3399_iomux_attach(device_t, device_t, void *); | 206 | static void rk3399_iomux_attach(device_t, device_t, void *); | |
207 | 207 | |||
208 | CFATTACH_DECL_NEW(rk3399_iomux, sizeof(struct rk3399_iomux_softc), | 208 | CFATTACH_DECL_NEW(rk3399_iomux, sizeof(struct rk3399_iomux_softc), | |
209 | rk3399_iomux_match, rk3399_iomux_attach, NULL, NULL); | 209 | rk3399_iomux_match, rk3399_iomux_attach, NULL, NULL); | |
210 | 210 | |||
211 | static void | 211 | static void | |
212 | rk3399_iomux_set_bias(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, int flags) | 212 | rk3399_iomux_set_bias(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, int flags) | |
213 | { | 213 | { | |
214 | const struct rk3399_iomux_bank *banks = sc->sc_conf->banks; | 214 | const struct rk3399_iomux_bank *banks = sc->sc_conf->banks; | |
215 | bus_size_t reg; | 215 | bus_size_t reg; | |
216 | u_int bias; | 216 | u_int bias; | |
217 | 217 | |||
218 | KASSERT(bank < sc->sc_conf->nbanks); | 218 | KASSERT(bank < sc->sc_conf->nbanks); | |
219 | 219 | |||
220 | struct syscon * const syscon = sc->sc_syscon[banks[bank].regs]; | 220 | struct syscon * const syscon = sc->sc_syscon[banks[bank].regs]; | |
221 | if (RK3399_IOMUX_BANK_IS_PMU(bank)) { | 221 | if (RK3399_IOMUX_BANK_IS_PMU(bank)) { | |
222 | reg = 0x00040 + (0x10 * bank); | 222 | reg = 0x00040 + (0x10 * bank); | |
223 | } else { | 223 | } else { | |
224 | reg = 0x0e040 + (0x10 * (bank - 2)); | 224 | reg = 0x0e040 + (0x10 * (bank - 2)); | |
225 | } | 225 | } | |
226 | reg += 0x4 * (idx / 8); | 226 | reg += 0x4 * (idx / 8); | |
227 | 227 | |||
228 | const int pull_type = banks[bank].iomux[idx / 8].pull_type; | 228 | const int pull_type = banks[bank].iomux[idx / 8].pull_type; | |
229 | 229 | |||
230 | if (flags == GPIO_PIN_PULLUP) { | 230 | if (flags == GPIO_PIN_PULLUP) { | |
231 | bias = pull_type == RK3399_PULL_TYPE_IO_DEFAULT ? | 231 | bias = pull_type == RK3399_PULL_TYPE_IO_DEFAULT ? | |
232 | IO_DEF_GPIO_P_CTL_PULLUP : | 232 | IO_DEF_GPIO_P_CTL_PULLUP : | |
233 | IO_1V8_GPIO_P_CTL_PULLUP; | 233 | IO_1V8_GPIO_P_CTL_PULLUP; | |
234 | } else if (flags == GPIO_PIN_PULLDOWN) { | 234 | } else if (flags == GPIO_PIN_PULLDOWN) { | |
235 | bias = pull_type == RK3399_PULL_TYPE_IO_DEFAULT ? | 235 | bias = pull_type == RK3399_PULL_TYPE_IO_DEFAULT ? | |
236 | IO_DEF_GPIO_P_CTL_PULLDOWN : | 236 | IO_DEF_GPIO_P_CTL_PULLDOWN : | |
237 | IO_1V8_GPIO_P_CTL_PULLDOWN; | 237 | IO_1V8_GPIO_P_CTL_PULLDOWN; | |
238 | } else { | 238 | } else { | |
239 | bias = pull_type == RK3399_PULL_TYPE_IO_DEFAULT ? | 239 | bias = pull_type == RK3399_PULL_TYPE_IO_DEFAULT ? | |
240 | IO_DEF_GPIO_P_CTL_Z : | 240 | IO_DEF_GPIO_P_CTL_Z : | |
241 | IO_1V8_GPIO_P_CTL_Z; | 241 | IO_1V8_GPIO_P_CTL_Z; | |
242 | } | 242 | } | |
243 | 243 | |||
244 | const uint32_t bias_val = __SHIFTIN(bias, GRF_GPIO_P_CTL(idx)); | 244 | const uint32_t bias_val = __SHIFTIN(bias, GRF_GPIO_P_CTL(idx)); | |
245 | const uint32_t bias_mask = GRF_GPIO_P_WRITE_EN(idx); | 245 | const uint32_t bias_mask = GRF_GPIO_P_WRITE_EN(idx); | |
246 | 246 | |||
247 | #ifdef RK3399_IOMUX_DEBUG | 247 | #ifdef RK3399_IOMUX_DEBUG | |
248 | printf("%s: bank %d idx %d flags %#x: %08x -> ", __func__, bank, idx, flags, RD4(syscon, reg)); | 248 | printf("%s: bank %d idx %d flags %#x: %08x -> ", __func__, bank, idx, flags, RD4(syscon, reg)); | |
249 | #endif | 249 | #endif | |
250 | WR4(syscon, reg, bias_val | bias_mask); | 250 | WR4(syscon, reg, bias_val | bias_mask); | |
251 | #ifdef RK3399_IOMUX_DEBUG | 251 | #ifdef RK3399_IOMUX_DEBUG | |
252 | printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg); | 252 | printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg); | |
253 | #endif | 253 | #endif | |
254 | } | 254 | } | |
255 | 255 | |||
256 | static int | 256 | static int | |
257 | rk3399_iomux_map_drive_strength(struct rk3399_iomux_softc *sc, enum rk3399_drv_type drv_type, u_int val) | 257 | rk3399_iomux_map_drive_strength(struct rk3399_iomux_softc *sc, enum rk3399_drv_type drv_type, u_int val) | |
258 | { | 258 | { | |
259 | for (int n = 0; rk3399_drv_strength[drv_type][n] != -1; n++) | 259 | for (int n = 0; rk3399_drv_strength[drv_type][n] != -1; n++) | |
260 | if (rk3399_drv_strength[drv_type][n] == val) | 260 | if (rk3399_drv_strength[drv_type][n] == val) | |
261 | return n; | 261 | return n; | |
262 | return -1; | 262 | return -1; | |
263 | } | 263 | } | |
264 | 264 | |||
265 | static int | 265 | static int | |
266 | rk3399_iomux_set_drive_strength(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, u_int val) | 266 | rk3399_iomux_set_drive_strength(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, u_int val) | |
267 | { | 267 | { | |
268 | const struct rk3399_iomux_bank *banks = sc->sc_conf->banks; | 268 | const struct rk3399_iomux_bank *banks = sc->sc_conf->banks; | |
269 | uint32_t drv_mask, drv_val; | 269 | uint32_t drv_mask, drv_val; | |
270 | bus_size_t reg; | 270 | bus_size_t reg; | |
271 | 271 | |||
272 | KASSERT(bank < sc->sc_conf->nbanks); | 272 | KASSERT(bank < sc->sc_conf->nbanks); | |
273 | 273 | |||
274 | if (idx >= 32) | 274 | if (idx >= 32) | |
275 | return EINVAL; | 275 | return EINVAL; | |
276 | 276 | |||
277 | const int drv = rk3399_iomux_map_drive_strength(sc, banks[bank].iomux[idx / 8].drv_type, val); | 277 | const int drv = rk3399_iomux_map_drive_strength(sc, banks[bank].iomux[idx / 8].drv_type, val); | |
278 | if (drv == -1) | 278 | if (drv == -1) | |
279 | return EINVAL; | 279 | return EINVAL; | |
280 | 280 | |||
281 | struct syscon * const syscon = sc->sc_syscon[banks[bank].regs]; | 281 | struct syscon * const syscon = sc->sc_syscon[banks[bank].regs]; | |
282 | switch (bank) { | 282 | switch (bank) { | |
283 | case 0: | 283 | case 0: | |
284 | case 1: | 284 | case 1: | |
285 | reg = 0x00040 + (0x10 * bank) + 0x4 * (idx / 4); | 285 | reg = 0x00040 + (0x10 * bank) + 0x4 * (idx / 4); | |
286 | drv_mask = 0x3 << ((idx & 7) * 2); | 286 | drv_mask = 0x3 << ((idx & 7) * 2); | |
287 | break; | 287 | break; | |
288 | case 2: | 288 | case 2: | |
289 | reg = 0x0e100 + 0x4 * (idx / 4); | 289 | reg = 0x0e100 + 0x4 * (idx / 4); | |
290 | drv_mask = 0x3 << ((idx & 7) * 2); | 290 | drv_mask = 0x3 << ((idx & 7) * 2); | |
291 | break; | 291 | break; | |
292 | case 3: | 292 | case 3: | |
293 | switch (idx / 8) { | 293 | switch (idx / 8) { | |
294 | case 0: | 294 | case 0: | |
295 | case 1: | 295 | case 1: | |
296 | case 2: | 296 | case 2: | |
297 | reg = 0x0e110 + 0x8 * (idx / 4); | 297 | reg = 0x0e110 + 0x8 * (idx / 4); | |
298 | drv_mask = 0x7 << ((idx & 7) * 3); | 298 | drv_mask = 0x7 << ((idx & 7) * 3); | |
299 | break; | 299 | break; | |
300 | case 3: | 300 | case 3: | |
301 | reg = 0x0e128; | 301 | reg = 0x0e128; | |
302 | drv_mask = 0x3 << ((idx & 7) * 2); | 302 | drv_mask = 0x3 << ((idx & 7) * 2); | |
303 | break; | 303 | break; | |
304 | default: | 304 | default: | |
305 | return EINVAL; | 305 | return EINVAL; | |
306 | } | 306 | } | |
307 | break; | 307 | break; | |
308 | case 4: | 308 | case 4: | |
309 | switch (idx / 8) { | 309 | switch (idx / 8) { | |
310 | case 0: | 310 | case 0: | |
311 | reg = 0x0e12c; | 311 | reg = 0x0e12c; | |
312 | drv_mask = 0x3 << ((idx & 7) * 2); | 312 | drv_mask = 0x3 << ((idx & 7) * 2); | |
313 | break; | 313 | break; | |
314 | case 1: | 314 | case 1: | |
315 | reg = 0x0e130; | 315 | reg = 0x0e130; | |
316 | drv_mask = 0x7 << ((idx & 7) * 3); | 316 | drv_mask = 0x7 << ((idx & 7) * 3); | |
317 | break; | 317 | break; | |
318 | case 2: | 318 | case 2: | |
319 | reg = 0x0e138; | 319 | reg = 0x0e138; | |
320 | drv_mask = 0x3 << ((idx & 7) * 2); | 320 | drv_mask = 0x3 << ((idx & 7) * 2); | |
321 | break; | 321 | break; | |
322 | case 3: | 322 | case 3: | |
323 | reg = 0x0e13c; | 323 | reg = 0x0e13c; | |
324 | drv_mask = 0x3 << ((idx & 7) * 2); | 324 | drv_mask = 0x3 << ((idx & 7) * 2); | |
325 | break; | 325 | break; | |
326 | default: | 326 | default: | |
327 | return EINVAL; | 327 | return EINVAL; | |
328 | } | 328 | } | |
329 | break; | 329 | break; | |
330 | default: | 330 | default: | |
331 | return EINVAL; | 331 | return EINVAL; | |
332 | } | 332 | } | |
333 | drv_val = __SHIFTIN(val, drv_mask); | 333 | drv_val = __SHIFTIN(val, drv_mask); | |
334 | 334 | |||
335 | while (drv_mask) { | 335 | while (drv_mask) { | |
336 | const uint32_t write_val = drv_val & 0xffff; | 336 | const uint32_t write_val = drv_val & 0xffff; | |
337 | const uint32_t write_mask = (drv_mask & 0xffff) << 16; | 337 | const uint32_t write_mask = (drv_mask & 0xffff) << 16; | |
338 | if (write_mask) { | 338 | if (write_mask) { | |
339 | #ifdef RK3399_IOMUX_DEBUG | 339 | #ifdef RK3399_IOMUX_DEBUG | |
340 | printf("%s: bank %d idx %d val %d: %08x -> ", __func__, bank, idx, val, RD4(syscon, reg)); | 340 | printf("%s: bank %d idx %d val %d: %08x -> ", __func__, bank, idx, val, RD4(syscon, reg)); | |
341 | #endif | 341 | #endif | |
342 | WR4(syscon, reg, write_val | write_mask); | 342 | WR4(syscon, reg, write_val | write_mask); | |
343 | #ifdef RK3399_IOMUX_DEBUG | 343 | #ifdef RK3399_IOMUX_DEBUG | |
344 | printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg); | 344 | printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg); | |
345 | #endif | 345 | #endif | |
346 | } | 346 | } | |
347 | reg += 0x4; | 347 | reg += 0x4; | |
348 | drv_val >>= 16; | 348 | drv_val >>= 16; | |
349 | drv_mask >>= 16; | 349 | drv_mask >>= 16; | |
350 | } | 350 | } | |
351 | 351 | |||
352 | return 0; | 352 | return 0; | |
353 | } | 353 | } | |
354 | 354 | |||
355 | static void | 355 | static void | |
356 | rk3399_iomux_set_mux(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, u_int mux) | 356 | rk3399_iomux_set_mux(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, u_int mux) | |
357 | { | 357 | { | |
358 | const struct rk3399_iomux_bank *banks = sc->sc_conf->banks; | 358 | const struct rk3399_iomux_bank *banks = sc->sc_conf->banks; | |
359 | bus_size_t reg; | 359 | bus_size_t reg; | |
360 | uint32_t mask; | 360 | uint32_t mask; | |
361 | 361 | |||
362 | KASSERT(bank < sc->sc_conf->nbanks); | 362 | KASSERT(bank < sc->sc_conf->nbanks); | |
363 | 363 | |||
364 | struct syscon * const syscon = sc->sc_syscon[banks[bank].regs]; | 364 | struct syscon * const syscon = sc->sc_syscon[banks[bank].regs]; | |
365 | if (RK3399_IOMUX_BANK_IS_PMU(bank)) { | 365 | if (RK3399_IOMUX_BANK_IS_PMU(bank)) { | |
366 | reg = 0x00000 + (0x10 * bank); | 366 | reg = 0x00000 + (0x10 * bank); | |
367 | } else { | 367 | } else { | |
368 | reg = 0x0e000 + (0x10 * (bank - 2)); | 368 | reg = 0x0e000 + (0x10 * (bank - 2)); | |
369 | } | 369 | } | |
370 | reg += 0x4 * (idx / 8); | 370 | reg += 0x4 * (idx / 8); | |
371 | mask = 3 << ((idx & 7) * 2); | 371 | mask = 3 << ((idx & 7) * 2); | |
372 | 372 | |||
373 | #ifdef RK3399_IOMUX_DEBUG | 373 | #ifdef RK3399_IOMUX_DEBUG | |
374 | printf("%s: bank %d idx %d mux %#x: %08x -> ", __func__, bank, idx, mux, RD4(syscon, reg)); | 374 | printf("%s: bank %d idx %d mux %#x: %08x -> ", __func__, bank, idx, mux, RD4(syscon, reg)); | |
375 | #endif | 375 | #endif | |
376 | WR4(syscon, reg, (mask << 16) | __SHIFTIN(mux, mask)); | 376 | WR4(syscon, reg, (mask << 16) | __SHIFTIN(mux, mask)); | |
377 | #ifdef RK3399_IOMUX_DEBUG | 377 | #ifdef RK3399_IOMUX_DEBUG | |
378 | printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg); | 378 | printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg); | |
379 | #endif | 379 | #endif | |
380 | } | 380 | } | |
381 | 381 | |||
382 | static int | 382 | static int | |
383 | rk3399_iomux_config(struct rk3399_iomux_softc *sc, const int phandle, u_int bank, u_int idx, u_int mux) | 383 | rk3399_iomux_config(struct rk3399_iomux_softc *sc, const int phandle, u_int bank, u_int idx, u_int mux) | |
384 | { | 384 | { | |
385 | 385 | |||
386 | const int bias = fdtbus_pinctrl_parse_bias(phandle, NULL); | 386 | const int bias = fdtbus_pinctrl_parse_bias(phandle, NULL); | |
387 | if (bias != -1) | 387 | if (bias != -1) | |
388 | rk3399_iomux_set_bias(sc, bank, idx, bias); | 388 | rk3399_iomux_set_bias(sc, bank, idx, bias); | |
389 | 389 | |||
390 | const int drv = fdtbus_pinctrl_parse_drive_strength(phandle); | 390 | const int drv = fdtbus_pinctrl_parse_drive_strength(phandle); | |
391 | if (drv != -1 && | 391 | if (drv != -1 && | |
392 | rk3399_iomux_set_drive_strength(sc, bank, idx, drv) != 0) | 392 | rk3399_iomux_set_drive_strength(sc, bank, idx, drv) != 0) | |
393 | return EINVAL; | 393 | return EINVAL; | |
394 | 394 | |||
395 | #if notyet | 395 | #if notyet | |
396 | int output_value; | 396 | int output_value; | |
397 | const int direction = | 397 | const int direction = | |
398 | fdtbus_pinctrl_parse_input_output(phandle, &output_value); | 398 | fdtbus_pinctrl_parse_input_output(phandle, &output_value); | |
399 | if (direction != -1) { | 399 | if (direction != -1) { | |
400 | rk3399_iomux_set_direction(sc, bank, idx, direction, | 400 | rk3399_iomux_set_direction(sc, bank, idx, direction, | |
401 | output_value); | 401 | output_value); | |
402 | } | 402 | } | |
403 | #endif | 403 | #endif | |
404 | 404 | |||
405 | rk3399_iomux_set_mux(sc, bank, idx, mux); | 405 | rk3399_iomux_set_mux(sc, bank, idx, mux); | |
406 | 406 | |||
407 | return 0; | 407 | return 0; | |
408 | } | 408 | } | |
409 | 409 | |||
410 | static int | 410 | static int | |
411 | rk3399_iomux_pinctrl_set_config(device_t dev, const void *data, size_t len) | 411 | rk3399_iomux_pinctrl_set_config(device_t dev, const void *data, size_t len) | |
412 | { | 412 | { | |
413 | struct rk3399_iomux_softc * const sc = device_private(dev); | 413 | struct rk3399_iomux_softc * const sc = device_private(dev); | |
414 | const struct rk3399_iomux_bank *banks = sc->sc_conf->banks; | 414 | const struct rk3399_iomux_bank *banks = sc->sc_conf->banks; | |
415 | int pins_len; | 415 | int pins_len; | |
416 | 416 | |||
417 | if (len != 4) | 417 | if (len != 4) | |
418 | return -1; | 418 | return -1; | |
419 | 419 | |||
420 | const int phandle = fdtbus_get_phandle_from_native(be32dec(data)); | 420 | const int phandle = fdtbus_get_phandle_from_native(be32dec(data)); | |
421 | const u_int *pins = fdtbus_get_prop(phandle, "rockchip,pins", &pins_len); | 421 | const u_int *pins = fdtbus_get_prop(phandle, "rockchip,pins", &pins_len); | |
422 | 422 | |||
423 | while (pins_len >= 16) { | 423 | while (pins_len >= 16) { | |
424 | const u_int bank = be32toh(pins[0]); | 424 | const u_int bank = be32toh(pins[0]); | |
425 | const u_int idx = be32toh(pins[1]); | 425 | const u_int idx = be32toh(pins[1]); | |
426 | const u_int mux = be32toh(pins[2]); | 426 | const u_int mux = be32toh(pins[2]); | |
427 | const int cfg = fdtbus_get_phandle_from_native(be32toh(pins[3])); | 427 | const int cfg = fdtbus_get_phandle_from_native(be32toh(pins[3])); | |
428 | 428 | |||
429 | struct syscon * const syscon = sc->sc_syscon[banks[bank].regs]; | 429 | struct syscon * const syscon = sc->sc_syscon[banks[bank].regs]; | |
430 | LOCK(syscon); | 430 | LOCK(syscon); | |
431 | rk3399_iomux_config(sc, cfg, bank, idx, mux); | 431 | rk3399_iomux_config(sc, cfg, bank, idx, mux); | |
432 | UNLOCK(syscon); | 432 | UNLOCK(syscon); | |
433 | 433 | |||
434 | pins_len -= 16; | 434 | pins_len -= 16; | |
435 | pins += 4; | 435 | pins += 4; | |
436 | } | 436 | } | |
437 | 437 | |||
438 | return 0; | 438 | return 0; | |
439 | } | 439 | } | |
440 | 440 | |||
441 | static struct fdtbus_pinctrl_controller_func rk3399_iomux_pinctrl_funcs = { | 441 | static struct fdtbus_pinctrl_controller_func rk3399_iomux_pinctrl_funcs = { | |
442 | .set_config = rk3399_iomux_pinctrl_set_config, | 442 | .set_config = rk3399_iomux_pinctrl_set_config, | |
443 | }; | 443 | }; | |
444 | 444 | |||
445 | static int | 445 | static int | |
446 | rk3399_iomux_match(device_t parent, cfdata_t cf, void *aux) | 446 | rk3399_iomux_match(device_t parent, cfdata_t cf, void *aux) | |
447 | { | 447 | { | |
448 | struct fdt_attach_args * const faa = aux; | 448 | struct fdt_attach_args * const faa = aux; | |
449 | 449 | |||
450 | return of_match_compat_data(faa->faa_phandle, compat_data); | 450 | return of_match_compat_data(faa->faa_phandle, compat_data); | |
451 | } | 451 | } | |
452 | 452 | |||
453 | #ifdef RK3399_IOMUX_FORCE_ENABLE_SWJ_DP | 453 | #ifdef RK3399_IOMUX_FORCE_ENABLE_SWJ_DP | |
454 | /* | 454 | /* | |
455 | * This enables the SWJ-DP (Serial Wire JTAG Debug Port). | 455 | * This enables the SWJ-DP (Serial Wire JTAG Debug Port). | |
456 | * If you enable this you must also disable sdhc due to pin conflicts. | 456 | * If you enable this you must also disable sdhc due to pin conflicts. | |
457 | */ | 457 | */ | |
458 | static void | 458 | static void | |
459 | rk3399_iomux_force_enable_swj_dp(struct rk3399_iomux_softc * const sc) | 459 | rk3399_iomux_force_enable_swj_dp(struct rk3399_iomux_softc * const sc) | |
460 | { | 460 | { | |
461 | struct syscon * const syscon = sc->sc_syscon[RK_IOMUX_REGS_GRF]; | 461 | struct syscon * const syscon = sc->sc_syscon[RK_IOMUX_REGS_GRF]; | |
462 | uint32_t val; | 462 | uint32_t val; | |
463 | 463 | |||
464 | aprint_normal_dev(sc->sc_dev, "enabling on-chip debugging\n"); | 464 | aprint_normal_dev(sc->sc_dev, "enabling on-chip debugging\n"); | |
465 | #define GRF_GPIO4B_IOMUX 0xe024 | 465 | #define GRF_GPIO4B_IOMUX 0xe024 | |
466 | #define GRF_GPIO4B_IOMUX_TCK __BITS(5,4) | 466 | #define GRF_GPIO4B_IOMUX_TCK __BITS(5,4) | |
467 | #define GRF_GPIO4B_IOMUX_TMS __BITS(7,6) | 467 | #define GRF_GPIO4B_IOMUX_TMS __BITS(7,6) | |
468 | #define GRF_SOC_CON7 0xe21c | 468 | #define GRF_SOC_CON7 0xe21c | |
469 | #define GRF_SOC_CON7_FORCE_JTAG __BIT(12) | 469 | #define GRF_SOC_CON7_FORCE_JTAG __BIT(12) | |
470 | LOCK(syscon); | 470 | LOCK(syscon); | |
471 | val = RD4(syscon, GRF_GPIO4B_IOMUX); | 471 | val = RD4(syscon, GRF_GPIO4B_IOMUX); | |
472 | val &= ~(GRF_GPIO4B_IOMUX_TCK | GRF_GPIO4B_IOMUX_TMS); | 472 | val &= ~(GRF_GPIO4B_IOMUX_TCK | GRF_GPIO4B_IOMUX_TMS); | |
473 | val |= __SHIFTIN(0x2, GRF_GPIO4B_IOMUX_TCK); | 473 | val |= __SHIFTIN(0x2, GRF_GPIO4B_IOMUX_TCK); | |
474 | val |= __SHIFTIN(0x2, GRF_GPIO4B_IOMUX_TMS); | 474 | val |= __SHIFTIN(0x2, GRF_GPIO4B_IOMUX_TMS); | |
475 | WR4(syscon, GRF_GPIO4B_IOMUX, val); | 475 | WR4(syscon, GRF_GPIO4B_IOMUX, val); | |
476 | val = RD4(syscon, GRF_SOC_CON7); | 476 | val = RD4(syscon, GRF_SOC_CON7); | |
477 | val |= GRF_SOC_CON7_FORCE_JTAG; | 477 | val |= GRF_SOC_CON7_FORCE_JTAG; | |
478 | WR4(syscon, GRF_SOC_CON7, val); | 478 | WR4(syscon, GRF_SOC_CON7, val); | |
479 | UNLOCK(syscon); | 479 | UNLOCK(syscon); | |
480 | } | 480 | } | |
481 | #endif | 481 | #endif | |
482 | 482 | |||
483 | static void | 483 | static void | |
484 | rk3399_iomux_attach(device_t parent, device_t self, void *aux) | 484 | rk3399_iomux_attach(device_t parent, device_t self, void *aux) | |
485 | { | 485 | { | |
486 | struct rk3399_iomux_softc * const sc = device_private(self); | 486 | struct rk3399_iomux_softc * const sc = device_private(self); | |
487 | struct fdt_attach_args * const faa = aux; | 487 | struct fdt_attach_args * const faa = aux; | |
488 | const int phandle = faa->faa_phandle; | 488 | const int phandle = faa->faa_phandle; | |
489 | int child, sub; | 489 | int child, sub; | |
490 | 490 | |||
491 | sc->sc_dev = self; | 491 | sc->sc_dev = self; | |
492 | sc->sc_syscon[RK_IOMUX_REGS_GRF] = fdtbus_syscon_acquire(phandle, "rockchip,grf"); | 492 | sc->sc_syscon[RK_IOMUX_REGS_GRF] = fdtbus_syscon_acquire(phandle, "rockchip,grf"); | |
493 | if (sc->sc_syscon[RK_IOMUX_REGS_GRF] == NULL) { | 493 | if (sc->sc_syscon[RK_IOMUX_REGS_GRF] == NULL) { | |
494 | aprint_error(": couldn't acquire grf syscon\n"); | 494 | aprint_error(": couldn't acquire grf syscon\n"); | |
495 | return; | 495 | return; | |
496 | } | 496 | } | |
497 | sc->sc_syscon[RK_IOMUX_REGS_PMU] = fdtbus_syscon_acquire(phandle, "rockchip,pmu"); | 497 | sc->sc_syscon[RK_IOMUX_REGS_PMU] = fdtbus_syscon_acquire(phandle, "rockchip,pmu"); | |
498 | if (sc->sc_syscon[RK_IOMUX_REGS_PMU] == NULL) { | 498 | if (sc->sc_syscon[RK_IOMUX_REGS_PMU] == NULL) { | |
499 | aprint_error(": couldn't acquire pmu syscon\n"); | 499 | aprint_error(": couldn't acquire pmu syscon\n"); | |
500 | return; | 500 | return; | |
501 | } | 501 | } | |
502 | sc->sc_conf = of_search_compatible(phandle, compat_data)->data; | 502 | sc->sc_conf = of_search_compatible(phandle, compat_data)->data; | |
503 | 503 | |||
504 | aprint_naive("\n"); | 504 | aprint_naive("\n"); | |
505 | aprint_normal(": RK3399 IOMUX control\n"); | 505 | aprint_normal(": RK3399 IOMUX control\n"); | |
506 | 506 | |||
507 | for (child = OF_child(phandle); child; child = OF_peer(child)) { | 507 | for (child = OF_child(phandle); child; child = OF_peer(child)) { | |
508 | for (sub = OF_child(child); sub; sub = OF_peer(sub)) { | 508 | for (sub = OF_child(child); sub; sub = OF_peer(sub)) { | |
509 | if (!of_hasprop(sub, "rockchip,pins")) | 509 | if (!of_hasprop(sub, "rockchip,pins")) | |
510 | continue; | 510 | continue; | |
511 | fdtbus_register_pinctrl_config(self, sub, &rk3399_iomux_pinctrl_funcs); | 511 | fdtbus_register_pinctrl_config(self, sub, &rk3399_iomux_pinctrl_funcs); | |
512 | } | 512 | } | |
513 | } | 513 | } | |
514 | 514 | |||
515 | for (child = OF_child(phandle); child; child = OF_peer(child)) { | 515 | for (child = OF_child(phandle); child; child = OF_peer(child)) { | |
516 | struct fdt_attach_args cfaa = *faa; | 516 | struct fdt_attach_args cfaa = *faa; | |
517 | cfaa.faa_phandle = child; | 517 | cfaa.faa_phandle = child; | |
518 | cfaa.faa_name = fdtbus_get_string(child, "name"); | 518 | cfaa.faa_name = fdtbus_get_string(child, "name"); | |
519 | cfaa.faa_quiet = false; | 519 | cfaa.faa_quiet = false; | |
520 | 520 | |||
521 | config_found(self, &cfaa, NULL); | 521 | config_found(self, &cfaa, NULL); | |
522 | } | 522 | } | |
523 | 523 | |||
524 | #ifdef RK3399_IOMUX_FORCE_ENABLE_SWJ_DP | 524 | #ifdef RK3399_IOMUX_FORCE_ENABLE_SWJ_DP | |
525 | rk3399_iomux_force_enable_swj_dp(sc); | 525 | rk3399_iomux_force_enable_swj_dp(sc); | |
526 | #endif | 526 | #endif | |
527 | } | 527 | } |
--- src/sys/arch/arm/rockchip/rk_vop.c 2021/01/25 14:20:38 1.8
+++ src/sys/arch/arm/rockchip/rk_vop.c 2021/01/27 02:00:02 1.9
@@ -1,605 +1,605 @@ | @@ -1,605 +1,605 @@ | |||
1 | /* $NetBSD: rk_vop.c,v 1.8 2021/01/25 14:20:38 thorpej Exp $ */ | 1 | /* $NetBSD: rk_vop.c,v 1.9 2021/01/27 02:00:02 thorpej Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2019 Jared D. McNeill <jmcneill@invisible.ca> | 4 | * Copyright (c) 2019 Jared D. McNeill <jmcneill@invisible.ca> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include <sys/cdefs.h> | 29 | #include <sys/cdefs.h> | |
30 | __KERNEL_RCSID(0, "$NetBSD: rk_vop.c,v 1.8 2021/01/25 14:20:38 thorpej Exp $"); | 30 | __KERNEL_RCSID(0, "$NetBSD: rk_vop.c,v 1.9 2021/01/27 02:00:02 thorpej Exp $"); | |
31 | 31 | |||
32 | #include <sys/param.h> | 32 | #include <sys/param.h> | |
33 | #include <sys/bus.h> | 33 | #include <sys/bus.h> | |
34 | #include <sys/device.h> | 34 | #include <sys/device.h> | |
35 | #include <sys/intr.h> | 35 | #include <sys/intr.h> | |
36 | #include <sys/systm.h> | 36 | #include <sys/systm.h> | |
37 | #include <sys/kernel.h> | 37 | #include <sys/kernel.h> | |
38 | #include <sys/conf.h> | 38 | #include <sys/conf.h> | |
39 | #include <sys/sysctl.h> | 39 | #include <sys/sysctl.h> | |
40 | 40 | |||
41 | #include <drm/drmP.h> | 41 | #include <drm/drmP.h> | |
42 | #include <drm/drm_crtc.h> | 42 | #include <drm/drm_crtc.h> | |
43 | #include <drm/drm_crtc_helper.h> | 43 | #include <drm/drm_crtc_helper.h> | |
44 | #include <drm/drm_plane_helper.h> | 44 | #include <drm/drm_plane_helper.h> | |
45 | 45 | |||
46 | #include <dev/fdt/fdtvar.h> | 46 | #include <dev/fdt/fdtvar.h> | |
47 | #include <dev/fdt/fdt_port.h> | 47 | #include <dev/fdt/fdt_port.h> | |
48 | 48 | |||
49 | #include <arm/rockchip/rk_drm.h> | 49 | #include <arm/rockchip/rk_drm.h> | |
50 | 50 | |||
51 | #define VOP_REG_CFG_DONE 0x0000 | 51 | #define VOP_REG_CFG_DONE 0x0000 | |
52 | #define REG_LOAD_EN __BIT(0) | 52 | #define REG_LOAD_EN __BIT(0) | |
53 | #define VOP_SYS_CTRL 0x0008 | 53 | #define VOP_SYS_CTRL 0x0008 | |
54 | #define VOP_STANDBY_EN __BIT(22) | 54 | #define VOP_STANDBY_EN __BIT(22) | |
55 | #define MIPI_OUT_EN __BIT(15) | 55 | #define MIPI_OUT_EN __BIT(15) | |
56 | #define EDP_OUT_EN __BIT(14) | 56 | #define EDP_OUT_EN __BIT(14) | |
57 | #define HDMI_OUT_EN __BIT(13) | 57 | #define HDMI_OUT_EN __BIT(13) | |
58 | #define RGB_OUT_EN __BIT(12) | 58 | #define RGB_OUT_EN __BIT(12) | |
59 | #define VOP_DSP_CTRL0 0x0010 | 59 | #define VOP_DSP_CTRL0 0x0010 | |
60 | #define DSP_OUT_MODE __BITS(3,0) | 60 | #define DSP_OUT_MODE __BITS(3,0) | |
61 | #define DSP_OUT_MODE_RGB888 0 | 61 | #define DSP_OUT_MODE_RGB888 0 | |
62 | #define DSP_OUT_MODE_RGBaaa 15 | 62 | #define DSP_OUT_MODE_RGBaaa 15 | |
63 | #define VOP_DSP_CTRL1 0x0014 | 63 | #define VOP_DSP_CTRL1 0x0014 | |
64 | #define VOP_WIN0_CTRL 0x0030 | 64 | #define VOP_WIN0_CTRL 0x0030 | |
65 | #define WIN0_LB_MODE __BITS(7,5) | 65 | #define WIN0_LB_MODE __BITS(7,5) | |
66 | #define WIN0_LB_MODE_RGB_3840X2 2 | 66 | #define WIN0_LB_MODE_RGB_3840X2 2 | |
67 | #define WIN0_LB_MODE_RGB_2560X4 3 | 67 | #define WIN0_LB_MODE_RGB_2560X4 3 | |
68 | #define WIN0_LB_MODE_RGB_1920X5 4 | 68 | #define WIN0_LB_MODE_RGB_1920X5 4 | |
69 | #define WIN0_LB_MODE_RGB_1280X8 5 | 69 | #define WIN0_LB_MODE_RGB_1280X8 5 | |
70 | #define WIN0_DATA_FMT __BITS(3,1) | 70 | #define WIN0_DATA_FMT __BITS(3,1) | |
71 | #define WIN0_DATA_FMT_ARGB888 0 | 71 | #define WIN0_DATA_FMT_ARGB888 0 | |
72 | #define WIN0_EN __BIT(0) | 72 | #define WIN0_EN __BIT(0) | |
73 | #define VOP_WIN0_COLOR_KEY 0x0038 | 73 | #define VOP_WIN0_COLOR_KEY 0x0038 | |
74 | #define VOP_WIN0_VIR 0x003c | 74 | #define VOP_WIN0_VIR 0x003c | |
75 | #define WIN0_VIR_STRIDE __BITS(13,0) | 75 | #define WIN0_VIR_STRIDE __BITS(13,0) | |
76 | #define VOP_WIN0_YRGB_MST 0x0040 | 76 | #define VOP_WIN0_YRGB_MST 0x0040 | |
77 | #define VOP_WIN0_ACT_INFO 0x0048 | 77 | #define VOP_WIN0_ACT_INFO 0x0048 | |
78 | #define WIN0_ACT_HEIGHT __BITS(28,16) | 78 | #define WIN0_ACT_HEIGHT __BITS(28,16) | |
79 | #define WIN0_ACT_WIDTH __BITS(12,0) | 79 | #define WIN0_ACT_WIDTH __BITS(12,0) | |
80 | #define VOP_WIN0_DSP_INFO 0x004c | 80 | #define VOP_WIN0_DSP_INFO 0x004c | |
81 | #define WIN0_DSP_HEIGHT __BITS(27,16) | 81 | #define WIN0_DSP_HEIGHT __BITS(27,16) | |
82 | #define WIN0_DSP_WIDTH __BITS(11,0) | 82 | #define WIN0_DSP_WIDTH __BITS(11,0) | |
83 | #define VOP_WIN0_DSP_ST 0x0050 | 83 | #define VOP_WIN0_DSP_ST 0x0050 | |
84 | #define WIN0_DSP_YST __BITS(28,16) | 84 | #define WIN0_DSP_YST __BITS(28,16) | |
85 | #define WIN0_DSP_XST __BITS(12,0) | 85 | #define WIN0_DSP_XST __BITS(12,0) | |
86 | #define VOP_POST_DSP_HACT_INFO 0x0170 | 86 | #define VOP_POST_DSP_HACT_INFO 0x0170 | |
87 | #define DSP_HACT_ST_POST __BITS(28,16) | 87 | #define DSP_HACT_ST_POST __BITS(28,16) | |
88 | #define DSP_HACT_END_POST __BITS(12,0) | 88 | #define DSP_HACT_END_POST __BITS(12,0) | |
89 | #define VOP_POST_DSP_VACT_INFO 0x0174 | 89 | #define VOP_POST_DSP_VACT_INFO 0x0174 | |
90 | #define DSP_VACT_ST_POST __BITS(28,16) | 90 | #define DSP_VACT_ST_POST __BITS(28,16) | |
91 | #define DSP_VACT_END_POST __BITS(12,0) | 91 | #define DSP_VACT_END_POST __BITS(12,0) | |
92 | #define VOP_DSP_HTOTAL_HS_END 0x0188 | 92 | #define VOP_DSP_HTOTAL_HS_END 0x0188 | |
93 | #define DSP_HS_END __BITS(28,16) | 93 | #define DSP_HS_END __BITS(28,16) | |
94 | #define DSP_HTOTAL __BITS(12,0) | 94 | #define DSP_HTOTAL __BITS(12,0) | |
95 | #define VOP_DSP_HACT_ST_END 0x018c | 95 | #define VOP_DSP_HACT_ST_END 0x018c | |
96 | #define DSP_HACT_ST __BITS(28,16) | 96 | #define DSP_HACT_ST __BITS(28,16) | |
97 | #define DSP_HACT_END __BITS(12,0) | 97 | #define DSP_HACT_END __BITS(12,0) | |
98 | #define VOP_DSP_VTOTAL_VS_END 0x0190 | 98 | #define VOP_DSP_VTOTAL_VS_END 0x0190 | |
99 | #define DSP_VS_END __BITS(28,16) | 99 | #define DSP_VS_END __BITS(28,16) | |
100 | #define DSP_VTOTAL __BITS(12,0) | 100 | #define DSP_VTOTAL __BITS(12,0) | |
101 | #define VOP_DSP_VACT_ST_END 0x0194 | 101 | #define VOP_DSP_VACT_ST_END 0x0194 | |
102 | #define DSP_VACT_ST __BITS(28,16) | 102 | #define DSP_VACT_ST __BITS(28,16) | |
103 | #define DSP_VACT_END __BITS(12,0) | 103 | #define DSP_VACT_END __BITS(12,0) | |
104 | 104 | |||
105 | /* | 105 | /* | |
106 | * Polarity fields are in different locations depending on SoC and output type, | 106 | * Polarity fields are in different locations depending on SoC and output type, | |
107 | * but always in the same order. | 107 | * but always in the same order. | |
108 | */ | 108 | */ | |
109 | #define DSP_DCLK_POL __BIT(3) | 109 | #define DSP_DCLK_POL __BIT(3) | |
110 | #define DSP_DEN_POL __BIT(2) | 110 | #define DSP_DEN_POL __BIT(2) | |
111 | #define DSP_VSYNC_POL __BIT(1) | 111 | #define DSP_VSYNC_POL __BIT(1) | |
112 | #define DSP_HSYNC_POL __BIT(0) | 112 | #define DSP_HSYNC_POL __BIT(0) | |
113 | 113 | |||
114 | enum vop_ep_type { | 114 | enum vop_ep_type { | |
115 | VOP_EP_MIPI, | 115 | VOP_EP_MIPI, | |
116 | VOP_EP_EDP, | 116 | VOP_EP_EDP, | |
117 | VOP_EP_HDMI, | 117 | VOP_EP_HDMI, | |
118 | VOP_EP_MIPI1, | 118 | VOP_EP_MIPI1, | |
119 | VOP_EP_DP, | 119 | VOP_EP_DP, | |
120 | VOP_NEP | 120 | VOP_NEP | |
121 | }; | 121 | }; | |
122 | 122 | |||
123 | struct rk_vop_softc; | 123 | struct rk_vop_softc; | |
124 | struct rk_vop_config; | 124 | struct rk_vop_config; | |
125 | 125 | |||
126 | struct rk_vop_crtc { | 126 | struct rk_vop_crtc { | |
127 | struct drm_crtc base; | 127 | struct drm_crtc base; | |
128 | struct rk_vop_softc *sc; | 128 | struct rk_vop_softc *sc; | |
129 | }; | 129 | }; | |
130 | 130 | |||
131 | struct rk_vop_softc { | 131 | struct rk_vop_softc { | |
132 | device_t sc_dev; | 132 | device_t sc_dev; | |
133 | bus_space_tag_t sc_bst; | 133 | bus_space_tag_t sc_bst; | |
134 | bus_space_handle_t sc_bsh; | 134 | bus_space_handle_t sc_bsh; | |
135 | int sc_phandle; | 135 | int sc_phandle; | |
136 | 136 | |||
137 | struct clk *sc_dclk; | 137 | struct clk *sc_dclk; | |
138 | 138 | |||
139 | struct rk_vop_crtc sc_crtc; | 139 | struct rk_vop_crtc sc_crtc; | |
140 | 140 | |||
141 | struct fdt_device_ports sc_ports; | 141 | struct fdt_device_ports sc_ports; | |
142 | 142 | |||
143 | const struct rk_vop_config *sc_conf; | 143 | const struct rk_vop_config *sc_conf; | |
144 | }; | 144 | }; | |
145 | 145 | |||
146 | #define to_rk_vop_crtc(x) container_of(x, struct rk_vop_crtc, base) | 146 | #define to_rk_vop_crtc(x) container_of(x, struct rk_vop_crtc, base) | |
147 | 147 | |||
148 | #define RD4(sc, reg) \ | 148 | #define RD4(sc, reg) \ | |
149 | bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) | 149 | bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) | |
150 | #define WR4(sc, reg, val) \ | 150 | #define WR4(sc, reg, val) \ | |
151 | bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) | 151 | bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) | |
152 | 152 | |||
153 | struct rk_vop_config { | 153 | struct rk_vop_config { | |
154 | const char *descr; | 154 | const char *descr; | |
155 | u_int out_mode; | 155 | u_int out_mode; | |
156 | void (*init)(struct rk_vop_softc *); | 156 | void (*init)(struct rk_vop_softc *); | |
157 | void (*set_polarity)(struct rk_vop_softc *, | 157 | void (*set_polarity)(struct rk_vop_softc *, | |
158 | enum vop_ep_type, uint32_t); | 158 | enum vop_ep_type, uint32_t); | |
159 | }; | 159 | }; | |
160 | 160 | |||
161 | #define RK3399_VOP_MIPI_POL __BITS(31,28) | 161 | #define RK3399_VOP_MIPI_POL __BITS(31,28) | |
162 | #define RK3399_VOP_EDP_POL __BITS(27,24) | 162 | #define RK3399_VOP_EDP_POL __BITS(27,24) | |
163 | #define RK3399_VOP_HDMI_POL __BITS(23,20) | 163 | #define RK3399_VOP_HDMI_POL __BITS(23,20) | |
164 | #define RK3399_VOP_DP_POL __BITS(19,16) | 164 | #define RK3399_VOP_DP_POL __BITS(19,16) | |
165 | 165 | |||
166 | #define RK3399_VOP_SYS_CTRL_ENABLE __BIT(11) | 166 | #define RK3399_VOP_SYS_CTRL_ENABLE __BIT(11) | |
167 | 167 | |||
168 | static void | 168 | static void | |
169 | rk3399_vop_set_polarity(struct rk_vop_softc *sc, enum vop_ep_type ep_type, uint32_t pol) | 169 | rk3399_vop_set_polarity(struct rk_vop_softc *sc, enum vop_ep_type ep_type, uint32_t pol) | |
170 | { | 170 | { | |
171 | uint32_t mask, val; | 171 | uint32_t mask, val; | |
172 | 172 | |||
173 | switch (ep_type) { | 173 | switch (ep_type) { | |
174 | case VOP_EP_MIPI: | 174 | case VOP_EP_MIPI: | |
175 | case VOP_EP_MIPI1: | 175 | case VOP_EP_MIPI1: | |
176 | mask = RK3399_VOP_MIPI_POL; | 176 | mask = RK3399_VOP_MIPI_POL; | |
177 | break; | 177 | break; | |
178 | case VOP_EP_EDP: | 178 | case VOP_EP_EDP: | |
179 | mask = RK3399_VOP_EDP_POL; | 179 | mask = RK3399_VOP_EDP_POL; | |
180 | break; | 180 | break; | |
181 | case VOP_EP_HDMI: | 181 | case VOP_EP_HDMI: | |
182 | mask = RK3399_VOP_HDMI_POL; | 182 | mask = RK3399_VOP_HDMI_POL; | |
183 | break; | 183 | break; | |
184 | case VOP_EP_DP: | 184 | case VOP_EP_DP: | |
185 | mask = RK3399_VOP_DP_POL; | 185 | mask = RK3399_VOP_DP_POL; | |
186 | break; | 186 | break; | |
187 | default: | 187 | default: | |
188 | return; | 188 | return; | |
189 | } | 189 | } | |
190 | 190 | |||
191 | val = RD4(sc, VOP_DSP_CTRL1); | 191 | val = RD4(sc, VOP_DSP_CTRL1); | |
192 | val &= ~mask; | 192 | val &= ~mask; | |
193 | val |= __SHIFTIN(pol, mask); | 193 | val |= __SHIFTIN(pol, mask); | |
194 | WR4(sc, VOP_DSP_CTRL1, val); | 194 | WR4(sc, VOP_DSP_CTRL1, val); | |
195 | } | 195 | } | |
196 | 196 | |||
197 | static void | 197 | static void | |
198 | rk3399_vop_init(struct rk_vop_softc *sc) | 198 | rk3399_vop_init(struct rk_vop_softc *sc) | |
199 | { | 199 | { | |
200 | uint32_t val; | 200 | uint32_t val; | |
201 | 201 | |||
202 | val = RD4(sc, VOP_SYS_CTRL); | 202 | val = RD4(sc, VOP_SYS_CTRL); | |
203 | val |= RK3399_VOP_SYS_CTRL_ENABLE; | 203 | val |= RK3399_VOP_SYS_CTRL_ENABLE; | |
204 | WR4(sc, VOP_SYS_CTRL, val); | 204 | WR4(sc, VOP_SYS_CTRL, val); | |
205 | } | 205 | } | |
206 | 206 | |||
207 | static const struct rk_vop_config rk3399_vop_lit_config = { | 207 | static const struct rk_vop_config rk3399_vop_lit_config = { | |
208 | .descr = "RK3399 VOPL", | 208 | .descr = "RK3399 VOPL", | |
209 | .out_mode = DSP_OUT_MODE_RGB888, | 209 | .out_mode = DSP_OUT_MODE_RGB888, | |
210 | .init = rk3399_vop_init, | 210 | .init = rk3399_vop_init, | |
211 | .set_polarity = rk3399_vop_set_polarity, | 211 | .set_polarity = rk3399_vop_set_polarity, | |
212 | }; | 212 | }; | |
213 | 213 | |||
214 | static const struct rk_vop_config rk3399_vop_big_config = { | 214 | static const struct rk_vop_config rk3399_vop_big_config = { | |
215 | .descr = "RK3399 VOPB", | 215 | .descr = "RK3399 VOPB", | |
216 | .out_mode = DSP_OUT_MODE_RGBaaa, | 216 | .out_mode = DSP_OUT_MODE_RGBaaa, | |
217 | .init = rk3399_vop_init, | 217 | .init = rk3399_vop_init, | |
218 | .set_polarity = rk3399_vop_set_polarity, | 218 | .set_polarity = rk3399_vop_set_polarity, | |
219 | }; | 219 | }; | |
220 | 220 | |||
221 | static const struct device_compatible_entry compat_data[] = { | 221 | static const struct device_compatible_entry compat_data[] = { | |
222 | { .compat = "rockchip,rk3399-vop-big", | 222 | { .compat = "rockchip,rk3399-vop-big", | |
223 | .data = &rk3399_vop_big_config }, | 223 | .data = &rk3399_vop_big_config }, | |
224 | { .compat = "rockchip,rk3399-vop-lit", | 224 | { .compat = "rockchip,rk3399-vop-lit", | |
225 | .data = &rk3399_vop_lit_config }, | 225 | .data = &rk3399_vop_lit_config }, | |
226 | 226 | |||
227 | { } | 227 | DEVICE_COMPAT_EOL | |
228 | }; | 228 | }; | |
229 | 229 | |||
230 | static int | 230 | static int | |
231 | rk_vop_mode_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb, | 231 | rk_vop_mode_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |
232 | int x, int y, int atomic) | 232 | int x, int y, int atomic) | |
233 | { | 233 | { | |
234 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | 234 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | |
235 | struct rk_vop_softc * const sc = mixer_crtc->sc; | 235 | struct rk_vop_softc * const sc = mixer_crtc->sc; | |
236 | struct rk_drm_framebuffer *sfb = atomic? | 236 | struct rk_drm_framebuffer *sfb = atomic? | |
237 | to_rk_drm_framebuffer(fb) : | 237 | to_rk_drm_framebuffer(fb) : | |
238 | to_rk_drm_framebuffer(crtc->primary->fb); | 238 | to_rk_drm_framebuffer(crtc->primary->fb); | |
239 | 239 | |||
240 | uint64_t paddr = (uint64_t)sfb->obj->dmamap->dm_segs[0].ds_addr; | 240 | uint64_t paddr = (uint64_t)sfb->obj->dmamap->dm_segs[0].ds_addr; | |
241 | 241 | |||
242 | 242 | |||
243 | paddr += y * sfb->base.pitches[0]; | 243 | paddr += y * sfb->base.pitches[0]; | |
244 | paddr += x * drm_format_plane_cpp(sfb->base.pixel_format, 0); | 244 | paddr += x * drm_format_plane_cpp(sfb->base.pixel_format, 0); | |
245 | 245 | |||
246 | KASSERT((paddr & ~0xffffffff) == 0); | 246 | KASSERT((paddr & ~0xffffffff) == 0); | |
247 | 247 | |||
248 | const uint32_t vir = __SHIFTIN(sfb->base.pitches[0] / 4, | 248 | const uint32_t vir = __SHIFTIN(sfb->base.pitches[0] / 4, | |
249 | WIN0_VIR_STRIDE); | 249 | WIN0_VIR_STRIDE); | |
250 | WR4(sc, VOP_WIN0_VIR, vir); | 250 | WR4(sc, VOP_WIN0_VIR, vir); | |
251 | 251 | |||
252 | /* Framebuffer start address */ | 252 | /* Framebuffer start address */ | |
253 | WR4(sc, VOP_WIN0_YRGB_MST, (uint32_t)paddr); | 253 | WR4(sc, VOP_WIN0_YRGB_MST, (uint32_t)paddr); | |
254 | 254 | |||
255 | return 0; | 255 | return 0; | |
256 | } | 256 | } | |
257 | 257 | |||
258 | static void | 258 | static void | |
259 | rk_vop_destroy(struct drm_crtc *crtc) | 259 | rk_vop_destroy(struct drm_crtc *crtc) | |
260 | { | 260 | { | |
261 | drm_crtc_cleanup(crtc); | 261 | drm_crtc_cleanup(crtc); | |
262 | } | 262 | } | |
263 | 263 | |||
264 | static const struct drm_crtc_funcs rk_vop_crtc_funcs = { | 264 | static const struct drm_crtc_funcs rk_vop_crtc_funcs = { | |
265 | .set_config = drm_crtc_helper_set_config, | 265 | .set_config = drm_crtc_helper_set_config, | |
266 | .destroy = rk_vop_destroy, | 266 | .destroy = rk_vop_destroy, | |
267 | }; | 267 | }; | |
268 | 268 | |||
269 | static void | 269 | static void | |
270 | rk_vop_dpms(struct drm_crtc *crtc, int mode) | 270 | rk_vop_dpms(struct drm_crtc *crtc, int mode) | |
271 | { | 271 | { | |
272 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | 272 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | |
273 | struct rk_vop_softc * const sc = mixer_crtc->sc; | 273 | struct rk_vop_softc * const sc = mixer_crtc->sc; | |
274 | uint32_t val; | 274 | uint32_t val; | |
275 | 275 | |||
276 | val = RD4(sc, VOP_SYS_CTRL); | 276 | val = RD4(sc, VOP_SYS_CTRL); | |
277 | 277 | |||
278 | switch (mode) { | 278 | switch (mode) { | |
279 | case DRM_MODE_DPMS_ON: | 279 | case DRM_MODE_DPMS_ON: | |
280 | val &= ~VOP_STANDBY_EN; | 280 | val &= ~VOP_STANDBY_EN; | |
281 | break; | 281 | break; | |
282 | case DRM_MODE_DPMS_STANDBY: | 282 | case DRM_MODE_DPMS_STANDBY: | |
283 | case DRM_MODE_DPMS_SUSPEND: | 283 | case DRM_MODE_DPMS_SUSPEND: | |
284 | case DRM_MODE_DPMS_OFF: | 284 | case DRM_MODE_DPMS_OFF: | |
285 | val |= VOP_STANDBY_EN; | 285 | val |= VOP_STANDBY_EN; | |
286 | break; | 286 | break; | |
287 | } | 287 | } | |
288 | 288 | |||
289 | WR4(sc, VOP_SYS_CTRL, val); | 289 | WR4(sc, VOP_SYS_CTRL, val); | |
290 | 290 | |||
291 | /* Commit settings */ | 291 | /* Commit settings */ | |
292 | WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); | 292 | WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); | |
293 | } | 293 | } | |
294 | 294 | |||
295 | static bool | 295 | static bool | |
296 | rk_vop_mode_fixup(struct drm_crtc *crtc, | 296 | rk_vop_mode_fixup(struct drm_crtc *crtc, | |
297 | const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) | 297 | const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) | |
298 | { | 298 | { | |
299 | return true; | 299 | return true; | |
300 | } | 300 | } | |
301 | 301 | |||
302 | static int | 302 | static int | |
303 | rk_vop_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, | 303 | rk_vop_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, | |
304 | struct drm_display_mode *adjusted_mode, int x, int y, | 304 | struct drm_display_mode *adjusted_mode, int x, int y, | |
305 | struct drm_framebuffer *old_fb) | 305 | struct drm_framebuffer *old_fb) | |
306 | { | 306 | { | |
307 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | 307 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | |
308 | struct rk_vop_softc * const sc = mixer_crtc->sc; | 308 | struct rk_vop_softc * const sc = mixer_crtc->sc; | |
309 | uint32_t val; | 309 | uint32_t val; | |
310 | u_int lb_mode; | 310 | u_int lb_mode; | |
311 | int error; | 311 | int error; | |
312 | u_int pol; | 312 | u_int pol; | |
313 | int connector_type = 0; | 313 | int connector_type = 0; | |
314 | struct drm_connector * connector; | 314 | struct drm_connector * connector; | |
315 | 315 | |||
316 | const u_int hactive = adjusted_mode->hdisplay; | 316 | const u_int hactive = adjusted_mode->hdisplay; | |
317 | const u_int hsync_len = adjusted_mode->hsync_end - adjusted_mode->hsync_start; | 317 | const u_int hsync_len = adjusted_mode->hsync_end - adjusted_mode->hsync_start; | |
318 | const u_int hback_porch = adjusted_mode->htotal - adjusted_mode->hsync_end; | 318 | const u_int hback_porch = adjusted_mode->htotal - adjusted_mode->hsync_end; | |
319 | const u_int hfront_porch = adjusted_mode->hsync_start - adjusted_mode->hdisplay; | 319 | const u_int hfront_porch = adjusted_mode->hsync_start - adjusted_mode->hdisplay; | |
320 | 320 | |||
321 | const u_int vactive = adjusted_mode->vdisplay; | 321 | const u_int vactive = adjusted_mode->vdisplay; | |
322 | const u_int vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start; | 322 | const u_int vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start; | |
323 | const u_int vback_porch = adjusted_mode->vtotal - adjusted_mode->vsync_end; | 323 | const u_int vback_porch = adjusted_mode->vtotal - adjusted_mode->vsync_end; | |
324 | const u_int vfront_porch = adjusted_mode->vsync_start - adjusted_mode->vdisplay; | 324 | const u_int vfront_porch = adjusted_mode->vsync_start - adjusted_mode->vdisplay; | |
325 | 325 | |||
326 | error = clk_set_rate(sc->sc_dclk, adjusted_mode->clock * 1000); | 326 | error = clk_set_rate(sc->sc_dclk, adjusted_mode->clock * 1000); | |
327 | if (error != 0) | 327 | if (error != 0) | |
328 | DRM_ERROR("couldn't set pixel clock: %d\n", error); | 328 | DRM_ERROR("couldn't set pixel clock: %d\n", error); | |
329 | 329 | |||
330 | val = __SHIFTIN(hactive - 1, WIN0_ACT_WIDTH) | | 330 | val = __SHIFTIN(hactive - 1, WIN0_ACT_WIDTH) | | |
331 | __SHIFTIN(vactive - 1, WIN0_ACT_HEIGHT); | 331 | __SHIFTIN(vactive - 1, WIN0_ACT_HEIGHT); | |
332 | WR4(sc, VOP_WIN0_ACT_INFO, val); | 332 | WR4(sc, VOP_WIN0_ACT_INFO, val); | |
333 | 333 | |||
334 | val = __SHIFTIN(hactive - 1, WIN0_DSP_WIDTH) | | 334 | val = __SHIFTIN(hactive - 1, WIN0_DSP_WIDTH) | | |
335 | __SHIFTIN(vactive - 1, WIN0_DSP_HEIGHT); | 335 | __SHIFTIN(vactive - 1, WIN0_DSP_HEIGHT); | |
336 | WR4(sc, VOP_WIN0_DSP_INFO, val); | 336 | WR4(sc, VOP_WIN0_DSP_INFO, val); | |
337 | 337 | |||
338 | val = __SHIFTIN(hsync_len + hback_porch, WIN0_DSP_XST) | | 338 | val = __SHIFTIN(hsync_len + hback_porch, WIN0_DSP_XST) | | |
339 | __SHIFTIN(vsync_len + vback_porch, WIN0_DSP_YST); | 339 | __SHIFTIN(vsync_len + vback_porch, WIN0_DSP_YST); | |
340 | WR4(sc, VOP_WIN0_DSP_ST, val); | 340 | WR4(sc, VOP_WIN0_DSP_ST, val); | |
341 | 341 | |||
342 | WR4(sc, VOP_WIN0_COLOR_KEY, 0); | 342 | WR4(sc, VOP_WIN0_COLOR_KEY, 0); | |
343 | 343 | |||
344 | if (adjusted_mode->hdisplay > 2560) | 344 | if (adjusted_mode->hdisplay > 2560) | |
345 | lb_mode = WIN0_LB_MODE_RGB_3840X2; | 345 | lb_mode = WIN0_LB_MODE_RGB_3840X2; | |
346 | else if (adjusted_mode->hdisplay > 1920) | 346 | else if (adjusted_mode->hdisplay > 1920) | |
347 | lb_mode = WIN0_LB_MODE_RGB_2560X4; | 347 | lb_mode = WIN0_LB_MODE_RGB_2560X4; | |
348 | else if (adjusted_mode->hdisplay > 1280) | 348 | else if (adjusted_mode->hdisplay > 1280) | |
349 | lb_mode = WIN0_LB_MODE_RGB_1920X5; | 349 | lb_mode = WIN0_LB_MODE_RGB_1920X5; | |
350 | else | 350 | else | |
351 | lb_mode = WIN0_LB_MODE_RGB_1280X8; | 351 | lb_mode = WIN0_LB_MODE_RGB_1280X8; | |
352 | 352 | |||
353 | val = __SHIFTIN(lb_mode, WIN0_LB_MODE) | | 353 | val = __SHIFTIN(lb_mode, WIN0_LB_MODE) | | |
354 | __SHIFTIN(WIN0_DATA_FMT_ARGB888, WIN0_DATA_FMT) | | 354 | __SHIFTIN(WIN0_DATA_FMT_ARGB888, WIN0_DATA_FMT) | | |
355 | WIN0_EN; | 355 | WIN0_EN; | |
356 | WR4(sc, VOP_WIN0_CTRL, val); | 356 | WR4(sc, VOP_WIN0_CTRL, val); | |
357 | 357 | |||
358 | rk_vop_mode_do_set_base(crtc, old_fb, x, y, 0); | 358 | rk_vop_mode_do_set_base(crtc, old_fb, x, y, 0); | |
359 | 359 | |||
360 | pol = DSP_DCLK_POL; | 360 | pol = DSP_DCLK_POL; | |
361 | if ((adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) != 0) | 361 | if ((adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) != 0) | |
362 | pol |= DSP_HSYNC_POL; | 362 | pol |= DSP_HSYNC_POL; | |
363 | if ((adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) != 0) | 363 | if ((adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) != 0) | |
364 | pol |= DSP_VSYNC_POL; | 364 | pol |= DSP_VSYNC_POL; | |
365 | 365 | |||
366 | drm_for_each_connector(connector, crtc->dev) { | 366 | drm_for_each_connector(connector, crtc->dev) { | |
367 | if ((connector->encoder) == NULL) | 367 | if ((connector->encoder) == NULL) | |
368 | continue; | 368 | continue; | |
369 | if (connector->encoder->crtc == crtc) { | 369 | if (connector->encoder->crtc == crtc) { | |
370 | connector_type = connector->connector_type; | 370 | connector_type = connector->connector_type; | |
371 | break; | 371 | break; | |
372 | } | 372 | } | |
373 | } | 373 | } | |
374 | 374 | |||
375 | switch (connector_type) { | 375 | switch (connector_type) { | |
376 | case DRM_MODE_CONNECTOR_HDMIA: | 376 | case DRM_MODE_CONNECTOR_HDMIA: | |
377 | sc->sc_conf->set_polarity(sc, VOP_EP_HDMI, pol); | 377 | sc->sc_conf->set_polarity(sc, VOP_EP_HDMI, pol); | |
378 | break; | 378 | break; | |
379 | case DRM_MODE_CONNECTOR_eDP: | 379 | case DRM_MODE_CONNECTOR_eDP: | |
380 | sc->sc_conf->set_polarity(sc, VOP_EP_EDP, pol); | 380 | sc->sc_conf->set_polarity(sc, VOP_EP_EDP, pol); | |
381 | break; | 381 | break; | |
382 | } | 382 | } | |
383 | 383 | |||
384 | val = RD4(sc, VOP_SYS_CTRL); | 384 | val = RD4(sc, VOP_SYS_CTRL); | |
385 | val &= ~VOP_STANDBY_EN; | 385 | val &= ~VOP_STANDBY_EN; | |
386 | val &= ~(MIPI_OUT_EN|EDP_OUT_EN|HDMI_OUT_EN|RGB_OUT_EN); | 386 | val &= ~(MIPI_OUT_EN|EDP_OUT_EN|HDMI_OUT_EN|RGB_OUT_EN); | |
387 | 387 | |||
388 | switch (connector_type) { | 388 | switch (connector_type) { | |
389 | case DRM_MODE_CONNECTOR_HDMIA: | 389 | case DRM_MODE_CONNECTOR_HDMIA: | |
390 | val |= HDMI_OUT_EN; | 390 | val |= HDMI_OUT_EN; | |
391 | break; | 391 | break; | |
392 | case DRM_MODE_CONNECTOR_eDP: | 392 | case DRM_MODE_CONNECTOR_eDP: | |
393 | val |= EDP_OUT_EN; | 393 | val |= EDP_OUT_EN; | |
394 | break; | 394 | break; | |
395 | } | 395 | } | |
396 | WR4(sc, VOP_SYS_CTRL, val); | 396 | WR4(sc, VOP_SYS_CTRL, val); | |
397 | 397 | |||
398 | val = RD4(sc, VOP_DSP_CTRL0); | 398 | val = RD4(sc, VOP_DSP_CTRL0); | |
399 | val &= ~DSP_OUT_MODE; | 399 | val &= ~DSP_OUT_MODE; | |
400 | val |= __SHIFTIN(sc->sc_conf->out_mode, DSP_OUT_MODE); | 400 | val |= __SHIFTIN(sc->sc_conf->out_mode, DSP_OUT_MODE); | |
401 | WR4(sc, VOP_DSP_CTRL0, val); | 401 | WR4(sc, VOP_DSP_CTRL0, val); | |
402 | 402 | |||
403 | val = __SHIFTIN(hsync_len + hback_porch, DSP_HACT_ST_POST) | | 403 | val = __SHIFTIN(hsync_len + hback_porch, DSP_HACT_ST_POST) | | |
404 | __SHIFTIN(hsync_len + hback_porch + hactive, DSP_HACT_END_POST); | 404 | __SHIFTIN(hsync_len + hback_porch + hactive, DSP_HACT_END_POST); | |
405 | WR4(sc, VOP_POST_DSP_HACT_INFO, val); | 405 | WR4(sc, VOP_POST_DSP_HACT_INFO, val); | |
406 | 406 | |||
407 | val = __SHIFTIN(hsync_len + hback_porch, DSP_HACT_ST) | | 407 | val = __SHIFTIN(hsync_len + hback_porch, DSP_HACT_ST) | | |
408 | __SHIFTIN(hsync_len + hback_porch + hactive, DSP_HACT_END); | 408 | __SHIFTIN(hsync_len + hback_porch + hactive, DSP_HACT_END); | |
409 | WR4(sc, VOP_DSP_HACT_ST_END, val); | 409 | WR4(sc, VOP_DSP_HACT_ST_END, val); | |
410 | 410 | |||
411 | val = __SHIFTIN(hsync_len, DSP_HTOTAL) | | 411 | val = __SHIFTIN(hsync_len, DSP_HTOTAL) | | |
412 | __SHIFTIN(hsync_len + hback_porch + hactive + hfront_porch, DSP_HS_END); | 412 | __SHIFTIN(hsync_len + hback_porch + hactive + hfront_porch, DSP_HS_END); | |
413 | WR4(sc, VOP_DSP_HTOTAL_HS_END, val); | 413 | WR4(sc, VOP_DSP_HTOTAL_HS_END, val); | |
414 | 414 | |||
415 | val = __SHIFTIN(vsync_len + vback_porch, DSP_VACT_ST_POST) | | 415 | val = __SHIFTIN(vsync_len + vback_porch, DSP_VACT_ST_POST) | | |
416 | __SHIFTIN(vsync_len + vback_porch + vactive, DSP_VACT_END_POST); | 416 | __SHIFTIN(vsync_len + vback_porch + vactive, DSP_VACT_END_POST); | |
417 | WR4(sc, VOP_POST_DSP_VACT_INFO, val); | 417 | WR4(sc, VOP_POST_DSP_VACT_INFO, val); | |
418 | 418 | |||
419 | val = __SHIFTIN(vsync_len + vback_porch, DSP_VACT_ST) | | 419 | val = __SHIFTIN(vsync_len + vback_porch, DSP_VACT_ST) | | |
420 | __SHIFTIN(vsync_len + vback_porch + vactive, DSP_VACT_END); | 420 | __SHIFTIN(vsync_len + vback_porch + vactive, DSP_VACT_END); | |
421 | WR4(sc, VOP_DSP_VACT_ST_END, val); | 421 | WR4(sc, VOP_DSP_VACT_ST_END, val); | |
422 | 422 | |||
423 | val = __SHIFTIN(vsync_len, DSP_VTOTAL) | | 423 | val = __SHIFTIN(vsync_len, DSP_VTOTAL) | | |
424 | __SHIFTIN(vsync_len + vback_porch + vactive + vfront_porch, DSP_VS_END); | 424 | __SHIFTIN(vsync_len + vback_porch + vactive + vfront_porch, DSP_VS_END); | |
425 | WR4(sc, VOP_DSP_VTOTAL_VS_END, val); | 425 | WR4(sc, VOP_DSP_VTOTAL_VS_END, val); | |
426 | 426 | |||
427 | return 0; | 427 | return 0; | |
428 | } | 428 | } | |
429 | 429 | |||
430 | static int | 430 | static int | |
431 | rk_vop_mode_set_base(struct drm_crtc *crtc, int x, int y, | 431 | rk_vop_mode_set_base(struct drm_crtc *crtc, int x, int y, | |
432 | struct drm_framebuffer *old_fb) | 432 | struct drm_framebuffer *old_fb) | |
433 | { | 433 | { | |
434 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | 434 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | |
435 | struct rk_vop_softc * const sc = mixer_crtc->sc; | 435 | struct rk_vop_softc * const sc = mixer_crtc->sc; | |
436 | 436 | |||
437 | rk_vop_mode_do_set_base(crtc, old_fb, x, y, 0); | 437 | rk_vop_mode_do_set_base(crtc, old_fb, x, y, 0); | |
438 | 438 | |||
439 | /* Commit settings */ | 439 | /* Commit settings */ | |
440 | WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); | 440 | WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); | |
441 | 441 | |||
442 | return 0; | 442 | return 0; | |
443 | } | 443 | } | |
444 | 444 | |||
445 | static int | 445 | static int | |
446 | rk_vop_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, | 446 | rk_vop_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |
447 | int x, int y, enum mode_set_atomic state) | 447 | int x, int y, enum mode_set_atomic state) | |
448 | { | 448 | { | |
449 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | 449 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | |
450 | struct rk_vop_softc * const sc = mixer_crtc->sc; | 450 | struct rk_vop_softc * const sc = mixer_crtc->sc; | |
451 | 451 | |||
452 | rk_vop_mode_do_set_base(crtc, fb, x, y, 1); | 452 | rk_vop_mode_do_set_base(crtc, fb, x, y, 1); | |
453 | 453 | |||
454 | /* Commit settings */ | 454 | /* Commit settings */ | |
455 | WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); | 455 | WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); | |
456 | 456 | |||
457 | return 0; | 457 | return 0; | |
458 | } | 458 | } | |
459 | 459 | |||
460 | static void | 460 | static void | |
461 | rk_vop_disable(struct drm_crtc *crtc) | 461 | rk_vop_disable(struct drm_crtc *crtc) | |
462 | { | 462 | { | |
463 | } | 463 | } | |
464 | 464 | |||
465 | static void | 465 | static void | |
466 | rk_vop_prepare(struct drm_crtc *crtc) | 466 | rk_vop_prepare(struct drm_crtc *crtc) | |
467 | { | 467 | { | |
468 | } | 468 | } | |
469 | 469 | |||
470 | static void | 470 | static void | |
471 | rk_vop_commit(struct drm_crtc *crtc) | 471 | rk_vop_commit(struct drm_crtc *crtc) | |
472 | { | 472 | { | |
473 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | 473 | struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); | |
474 | struct rk_vop_softc * const sc = mixer_crtc->sc; | 474 | struct rk_vop_softc * const sc = mixer_crtc->sc; | |
475 | 475 | |||
476 | /* Commit settings */ | 476 | /* Commit settings */ | |
477 | WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); | 477 | WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); | |
478 | } | 478 | } | |
479 | 479 | |||
480 | static const struct drm_crtc_helper_funcs rk_vop_crtc_helper_funcs = { | 480 | static const struct drm_crtc_helper_funcs rk_vop_crtc_helper_funcs = { | |
481 | .dpms = rk_vop_dpms, | 481 | .dpms = rk_vop_dpms, | |
482 | .mode_fixup = rk_vop_mode_fixup, | 482 | .mode_fixup = rk_vop_mode_fixup, | |
483 | .mode_set = rk_vop_mode_set, | 483 | .mode_set = rk_vop_mode_set, | |
484 | .mode_set_base = rk_vop_mode_set_base, | 484 | .mode_set_base = rk_vop_mode_set_base, | |
485 | .mode_set_base_atomic = rk_vop_mode_set_base_atomic, | 485 | .mode_set_base_atomic = rk_vop_mode_set_base_atomic, | |
486 | .disable = rk_vop_disable, | 486 | .disable = rk_vop_disable, | |
487 | .prepare = rk_vop_prepare, | 487 | .prepare = rk_vop_prepare, | |
488 | .commit = rk_vop_commit, | 488 | .commit = rk_vop_commit, | |
489 | }; | 489 | }; | |
490 | 490 | |||
491 | static int | 491 | static int | |
492 | rk_vop_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate) | 492 | rk_vop_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate) | |
493 | { | 493 | { | |
494 | struct rk_vop_softc * const sc = device_private(dev); | 494 | struct rk_vop_softc * const sc = device_private(dev); | |
495 | struct drm_device *ddev; | 495 | struct drm_device *ddev; | |
496 | 496 | |||
497 | if (!activate) | 497 | if (!activate) | |
498 | return EINVAL; | 498 | return EINVAL; | |
499 | 499 | |||
500 | ddev = rk_drm_port_device(&sc->sc_ports); | 500 | ddev = rk_drm_port_device(&sc->sc_ports); | |
501 | if (ddev == NULL) { | 501 | if (ddev == NULL) { | |
502 | DRM_ERROR("couldn't find DRM device\n"); | 502 | DRM_ERROR("couldn't find DRM device\n"); | |
503 | return ENXIO; | 503 | return ENXIO; | |
504 | } | 504 | } | |
505 | 505 | |||
506 | if (sc->sc_crtc.sc == NULL) { | 506 | if (sc->sc_crtc.sc == NULL) { | |
507 | sc->sc_crtc.sc = sc; | 507 | sc->sc_crtc.sc = sc; | |
508 | 508 | |||
509 | drm_crtc_init(ddev, &sc->sc_crtc.base, &rk_vop_crtc_funcs); | 509 | drm_crtc_init(ddev, &sc->sc_crtc.base, &rk_vop_crtc_funcs); | |
510 | drm_crtc_helper_add(&sc->sc_crtc.base, &rk_vop_crtc_helper_funcs); | 510 | drm_crtc_helper_add(&sc->sc_crtc.base, &rk_vop_crtc_helper_funcs); | |
511 | 511 | |||
512 | aprint_debug_dev(dev, "using CRTC %d for %s\n", | 512 | aprint_debug_dev(dev, "using CRTC %d for %s\n", | |
513 | drm_crtc_index(&sc->sc_crtc.base), sc->sc_conf->descr); | 513 | drm_crtc_index(&sc->sc_crtc.base), sc->sc_conf->descr); | |
514 | } | 514 | } | |
515 | 515 | |||
516 | const u_int ep_index = fdt_endpoint_index(ep); | 516 | const u_int ep_index = fdt_endpoint_index(ep); | |
517 | if (ep_index >= VOP_NEP) { | 517 | if (ep_index >= VOP_NEP) { | |
518 | DRM_ERROR("endpoint index %d out of range\n", ep_index); | 518 | DRM_ERROR("endpoint index %d out of range\n", ep_index); | |
519 | return ENXIO; | 519 | return ENXIO; | |
520 | } | 520 | } | |
521 | 521 | |||
522 | return fdt_endpoint_activate(ep, activate); | 522 | return fdt_endpoint_activate(ep, activate); | |
523 | } | 523 | } | |
524 | 524 | |||
525 | static void * | 525 | static void * | |
526 | rk_vop_ep_get_data(device_t dev, struct fdt_endpoint *ep) | 526 | rk_vop_ep_get_data(device_t dev, struct fdt_endpoint *ep) | |
527 | { | 527 | { | |
528 | struct rk_vop_softc * const sc = device_private(dev); | 528 | struct rk_vop_softc * const sc = device_private(dev); | |
529 | 529 | |||
530 | return &sc->sc_crtc.base; | 530 | return &sc->sc_crtc.base; | |
531 | } | 531 | } | |
532 | 532 | |||
533 | static int | 533 | static int | |
534 | rk_vop_match(device_t parent, cfdata_t cf, void *aux) | 534 | rk_vop_match(device_t parent, cfdata_t cf, void *aux) | |
535 | { | 535 | { | |
536 | struct fdt_attach_args * const faa = aux; | 536 | struct fdt_attach_args * const faa = aux; | |
537 | 537 | |||
538 | return of_match_compat_data(faa->faa_phandle, compat_data); | 538 | return of_match_compat_data(faa->faa_phandle, compat_data); | |
539 | } | 539 | } | |
540 | 540 | |||
541 | static void | 541 | static void | |
542 | rk_vop_attach(device_t parent, device_t self, void *aux) | 542 | rk_vop_attach(device_t parent, device_t self, void *aux) | |
543 | { | 543 | { | |
544 | struct rk_vop_softc * const sc = device_private(self); | 544 | struct rk_vop_softc * const sc = device_private(self); | |
545 | struct fdt_attach_args * const faa = aux; | 545 | struct fdt_attach_args * const faa = aux; | |
546 | const int phandle = faa->faa_phandle; | 546 | const int phandle = faa->faa_phandle; | |
547 | const char * const reset_names[] = { "axi", "ahb", "dclk" }; | 547 | const char * const reset_names[] = { "axi", "ahb", "dclk" }; | |
548 | const char * const clock_names[] = { "aclk_vop", "hclk_vop" }; | 548 | const char * const clock_names[] = { "aclk_vop", "hclk_vop" }; | |
549 | struct fdtbus_reset *rst; | 549 | struct fdtbus_reset *rst; | |
550 | bus_addr_t addr; | 550 | bus_addr_t addr; | |
551 | bus_size_t size; | 551 | bus_size_t size; | |
552 | u_int n; | 552 | u_int n; | |
553 | 553 | |||
554 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | 554 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | |
555 | aprint_error(": couldn't get registers\n"); | 555 | aprint_error(": couldn't get registers\n"); | |
556 | return; | 556 | return; | |
557 | } | 557 | } | |
558 | 558 | |||
559 | fdtbus_clock_assign(phandle); | 559 | fdtbus_clock_assign(phandle); | |
560 | 560 | |||
561 | for (n = 0; n < __arraycount(reset_names); n++) { | 561 | for (n = 0; n < __arraycount(reset_names); n++) { | |
562 | rst = fdtbus_reset_get(phandle, reset_names[n]); | 562 | rst = fdtbus_reset_get(phandle, reset_names[n]); | |
563 | if (rst == NULL || fdtbus_reset_deassert(rst) != 0) { | 563 | if (rst == NULL || fdtbus_reset_deassert(rst) != 0) { | |
564 | aprint_error(": couldn't de-assert reset %s\n", reset_names[n]); | 564 | aprint_error(": couldn't de-assert reset %s\n", reset_names[n]); | |
565 | return; | 565 | return; | |
566 | } | 566 | } | |
567 | } | 567 | } | |
568 | for (n = 0; n < __arraycount(clock_names); n++) { | 568 | for (n = 0; n < __arraycount(clock_names); n++) { | |
569 | if (fdtbus_clock_enable(phandle, clock_names[n], true) != 0) { | 569 | if (fdtbus_clock_enable(phandle, clock_names[n], true) != 0) { | |
570 | aprint_error(": couldn't enable clock %s\n", clock_names[n]); | 570 | aprint_error(": couldn't enable clock %s\n", clock_names[n]); | |
571 | return; | 571 | return; | |
572 | } | 572 | } | |
573 | } | 573 | } | |
574 | sc->sc_dclk = fdtbus_clock_get(phandle, "dclk_vop"); | 574 | sc->sc_dclk = fdtbus_clock_get(phandle, "dclk_vop"); | |
575 | if (sc->sc_dclk == NULL || clk_enable(sc->sc_dclk) != 0) { | 575 | if (sc->sc_dclk == NULL || clk_enable(sc->sc_dclk) != 0) { | |
576 | aprint_error(": couldn't enable clock %s\n", "dclk_vop"); | 576 | aprint_error(": couldn't enable clock %s\n", "dclk_vop"); | |
577 | return; | 577 | return; | |
578 | } | 578 | } | |
579 | 579 | |||
580 | sc->sc_dev = self; | 580 | sc->sc_dev = self; | |
581 | sc->sc_bst = faa->faa_bst; | 581 | sc->sc_bst = faa->faa_bst; | |
582 | if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { | 582 | if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { | |
583 | aprint_error(": couldn't map registers\n"); | 583 | aprint_error(": couldn't map registers\n"); | |
584 | return; | 584 | return; | |
585 | } | 585 | } | |
586 | sc->sc_phandle = faa->faa_phandle; | 586 | sc->sc_phandle = faa->faa_phandle; | |
587 | sc->sc_conf = of_search_compatible(phandle, compat_data)->data; | 587 | sc->sc_conf = of_search_compatible(phandle, compat_data)->data; | |
588 | 588 | |||
589 | aprint_naive("\n"); | 589 | aprint_naive("\n"); | |
590 | aprint_normal(": %s\n", sc->sc_conf->descr); | 590 | aprint_normal(": %s\n", sc->sc_conf->descr); | |
591 | 591 | |||
592 | if (sc->sc_conf->init != NULL) | 592 | if (sc->sc_conf->init != NULL) | |
593 | sc->sc_conf->init(sc); | 593 | sc->sc_conf->init(sc); | |
594 | 594 | |||
595 | sc->sc_ports.dp_ep_activate = rk_vop_ep_activate; | 595 | sc->sc_ports.dp_ep_activate = rk_vop_ep_activate; | |
596 | sc->sc_ports.dp_ep_get_data = rk_vop_ep_get_data; | 596 | sc->sc_ports.dp_ep_get_data = rk_vop_ep_get_data; | |
597 | fdt_ports_register(&sc->sc_ports, self, phandle, EP_DRM_CRTC); | 597 | fdt_ports_register(&sc->sc_ports, self, phandle, EP_DRM_CRTC); | |
598 | 598 | |||
599 | const int port_phandle = of_find_firstchild_byname(phandle, "port"); | 599 | const int port_phandle = of_find_firstchild_byname(phandle, "port"); | |
600 | if (port_phandle > 0) | 600 | if (port_phandle > 0) | |
601 | rk_drm_register_port(port_phandle, &sc->sc_ports); | 601 | rk_drm_register_port(port_phandle, &sc->sc_ports); | |
602 | } | 602 | } | |
603 | 603 | |||
604 | CFATTACH_DECL_NEW(rk_vop, sizeof(struct rk_vop_softc), | 604 | CFATTACH_DECL_NEW(rk_vop, sizeof(struct rk_vop_softc), | |
605 | rk_vop_match, rk_vop_attach, NULL, NULL); | 605 | rk_vop_match, rk_vop_attach, NULL, NULL); |
--- src/sys/arch/arm/rockchip/rk_pwm.c 2021/01/25 14:20:38 1.5
+++ src/sys/arch/arm/rockchip/rk_pwm.c 2021/01/27 02:00:02 1.6
@@ -1,249 +1,249 @@ | @@ -1,249 +1,249 @@ | |||
1 | /* $NetBSD: rk_pwm.c,v 1.5 2021/01/25 14:20:38 thorpej Exp $ */ | 1 | /* $NetBSD: rk_pwm.c,v 1.6 2021/01/27 02:00:02 thorpej Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca> | 4 | * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 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 | 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 | 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 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 | 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 | * POSSIBILITY OF SUCH DAMAGE. | 26 | * POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include <sys/cdefs.h> | 29 | #include <sys/cdefs.h> | |
30 | 30 | |||
31 | __KERNEL_RCSID(1, "$NetBSD: rk_pwm.c,v 1.5 2021/01/25 14:20:38 thorpej Exp $"); | 31 | __KERNEL_RCSID(1, "$NetBSD: rk_pwm.c,v 1.6 2021/01/27 02:00:02 thorpej Exp $"); | |
32 | 32 | |||
33 | #include <sys/param.h> | 33 | #include <sys/param.h> | |
34 | #include <sys/bus.h> | 34 | #include <sys/bus.h> | |
35 | #include <sys/device.h> | 35 | #include <sys/device.h> | |
36 | #include <sys/intr.h> | 36 | #include <sys/intr.h> | |
37 | #include <sys/systm.h> | 37 | #include <sys/systm.h> | |
38 | #include <sys/time.h> | 38 | #include <sys/time.h> | |
39 | 39 | |||
40 | #include <dev/pwm/pwmvar.h> | 40 | #include <dev/pwm/pwmvar.h> | |
41 | 41 | |||
42 | #include <dev/fdt/fdtvar.h> | 42 | #include <dev/fdt/fdtvar.h> | |
43 | 43 | |||
44 | #define PWM0_CNT 0x00 | 44 | #define PWM0_CNT 0x00 | |
45 | #define PWM0_PERIOD_HPR 0x04 | 45 | #define PWM0_PERIOD_HPR 0x04 | |
46 | #define PWM0_DUTY_LPR 0x08 | 46 | #define PWM0_DUTY_LPR 0x08 | |
47 | #define PWM0_CTRL 0x0c | 47 | #define PWM0_CTRL 0x0c | |
48 | #define CTRL_RPT __BITS(31,24) | 48 | #define CTRL_RPT __BITS(31,24) | |
49 | #define CTRL_SCALE __BITS(23,16) | 49 | #define CTRL_SCALE __BITS(23,16) | |
50 | #define CTRL_PRESCALE __BITS(14,12) | 50 | #define CTRL_PRESCALE __BITS(14,12) | |
51 | #define CTRL_CLK_SEL __BIT(9) | 51 | #define CTRL_CLK_SEL __BIT(9) | |
52 | #define CTRL_LP_EN __BIT(8) | 52 | #define CTRL_LP_EN __BIT(8) | |
53 | #define CTRL_OUTPUT_MODE __BIT(5) | 53 | #define CTRL_OUTPUT_MODE __BIT(5) | |
54 | #define CTRL_INACTIVE_POL __BIT(4) | 54 | #define CTRL_INACTIVE_POL __BIT(4) | |
55 | #define CTRL_DUTY_POL __BIT(3) | 55 | #define CTRL_DUTY_POL __BIT(3) | |
56 | #define CTRL_PWM_MODE __BITS(2,1) | 56 | #define CTRL_PWM_MODE __BITS(2,1) | |
57 | #define CTRL_PWM_MODE_ONESHOT 0 | 57 | #define CTRL_PWM_MODE_ONESHOT 0 | |
58 | #define CTRL_PWM_MODE_CONTINUOUS 1 | 58 | #define CTRL_PWM_MODE_CONTINUOUS 1 | |
59 | #define CTRL_PWM_MODE_CAPTURE 2 | 59 | #define CTRL_PWM_MODE_CAPTURE 2 | |
60 | #define CTRL_PWM_EN __BIT(0) | 60 | #define CTRL_PWM_EN __BIT(0) | |
61 | 61 | |||
62 | enum rk_pwm_type { | 62 | enum rk_pwm_type { | |
63 | PWM_RK3288 = 1, | 63 | PWM_RK3288 = 1, | |
64 | }; | 64 | }; | |
65 | 65 | |||
66 | static const struct device_compatible_entry compat_data[] = { | 66 | static const struct device_compatible_entry compat_data[] = { | |
67 | { .compat = "rockchip,rk3288-pwm", .value = PWM_RK3288 }, | 67 | { .compat = "rockchip,rk3288-pwm", .value = PWM_RK3288 }, | |
68 | { } | 68 | DEVICE_COMPAT_EOL | |
69 | }; | 69 | }; | |
70 | 70 | |||
71 | struct rk_pwm_softc { | 71 | struct rk_pwm_softc { | |
72 | device_t sc_dev; | 72 | device_t sc_dev; | |
73 | bus_space_tag_t sc_bst; | 73 | bus_space_tag_t sc_bst; | |
74 | bus_space_handle_t sc_bsh; | 74 | bus_space_handle_t sc_bsh; | |
75 | 75 | |||
76 | struct pwm_controller sc_pwm; | 76 | struct pwm_controller sc_pwm; | |
77 | struct pwm_config sc_conf; | 77 | struct pwm_config sc_conf; | |
78 | 78 | |||
79 | u_int sc_clkfreq; | 79 | u_int sc_clkfreq; | |
80 | }; | 80 | }; | |
81 | 81 | |||
82 | #define PWM_READ(sc, reg) \ | 82 | #define PWM_READ(sc, reg) \ | |
83 | bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) | 83 | bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) | |
84 | #define PWM_WRITE(sc, reg, val) \ | 84 | #define PWM_WRITE(sc, reg, val) \ | |
85 | bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) | 85 | bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) | |
86 | 86 | |||
87 | static pwm_tag_t | 87 | static pwm_tag_t | |
88 | rk_pwm_get_tag(device_t dev, const void *data, size_t len) | 88 | rk_pwm_get_tag(device_t dev, const void *data, size_t len) | |
89 | { | 89 | { | |
90 | struct rk_pwm_softc * const sc = device_private(dev); | 90 | struct rk_pwm_softc * const sc = device_private(dev); | |
91 | const u_int *pwm = data; | 91 | const u_int *pwm = data; | |
92 | 92 | |||
93 | if (len != 16) | 93 | if (len != 16) | |
94 | return NULL; | 94 | return NULL; | |
95 | 95 | |||
96 | const u_int index = be32toh(pwm[1]); | 96 | const u_int index = be32toh(pwm[1]); | |
97 | if (index != 0) | 97 | if (index != 0) | |
98 | return NULL; | 98 | return NULL; | |
99 | 99 | |||
100 | const u_int period = be32toh(pwm[2]); | 100 | const u_int period = be32toh(pwm[2]); | |
101 | const u_int polarity = be32toh(pwm[3]); | 101 | const u_int polarity = be32toh(pwm[3]); | |
102 | 102 | |||
103 | sc->sc_conf.period = period; | 103 | sc->sc_conf.period = period; | |
104 | sc->sc_conf.polarity = polarity ? PWM_ACTIVE_LOW : PWM_ACTIVE_HIGH; | 104 | sc->sc_conf.polarity = polarity ? PWM_ACTIVE_LOW : PWM_ACTIVE_HIGH; | |
105 | 105 | |||
106 | return &sc->sc_pwm; | 106 | return &sc->sc_pwm; | |
107 | } | 107 | } | |
108 | 108 | |||
109 | static struct fdtbus_pwm_controller_func rk_pwm_funcs = { | 109 | static struct fdtbus_pwm_controller_func rk_pwm_funcs = { | |
110 | .get_tag = rk_pwm_get_tag | 110 | .get_tag = rk_pwm_get_tag | |
111 | }; | 111 | }; | |
112 | 112 | |||
113 | static int | 113 | static int | |
114 | rk_pwm_enable(pwm_tag_t pwm, bool enable) | 114 | rk_pwm_enable(pwm_tag_t pwm, bool enable) | |
115 | { | 115 | { | |
116 | struct rk_pwm_softc * const sc = device_private(pwm->pwm_dev); | 116 | struct rk_pwm_softc * const sc = device_private(pwm->pwm_dev); | |
117 | uint32_t ctrl, octrl; | 117 | uint32_t ctrl, octrl; | |
118 | 118 | |||
119 | octrl = ctrl = PWM_READ(sc, PWM0_CTRL); | 119 | octrl = ctrl = PWM_READ(sc, PWM0_CTRL); | |
120 | if (enable) | 120 | if (enable) | |
121 | ctrl |= CTRL_PWM_EN; | 121 | ctrl |= CTRL_PWM_EN; | |
122 | else | 122 | else | |
123 | ctrl &= ~CTRL_PWM_EN; | 123 | ctrl &= ~CTRL_PWM_EN; | |
124 | 124 | |||
125 | if (ctrl != octrl) | 125 | if (ctrl != octrl) | |
126 | PWM_WRITE(sc, PWM0_CTRL, ctrl); | 126 | PWM_WRITE(sc, PWM0_CTRL, ctrl); | |
127 | 127 | |||
128 | return 0; | 128 | return 0; | |
129 | } | 129 | } | |
130 | 130 | |||
131 | static int | 131 | static int | |
132 | rk_pwm_get_config(pwm_tag_t pwm, struct pwm_config *conf) | 132 | rk_pwm_get_config(pwm_tag_t pwm, struct pwm_config *conf) | |
133 | { | 133 | { | |
134 | struct rk_pwm_softc * const sc = device_private(pwm->pwm_dev); | 134 | struct rk_pwm_softc * const sc = device_private(pwm->pwm_dev); | |
135 | 135 | |||
136 | #if 0 | 136 | #if 0 | |
137 | /* XXX may be useful someday */ | 137 | /* XXX may be useful someday */ | |
138 | 138 | |||
139 | uint32_t ctrl, period, duty; | 139 | uint32_t ctrl, period, duty; | |
140 | u_int div; | 140 | u_int div; | |
141 | 141 | |||
142 | ctrl = PWM_READ(sc, PWM0_CTRL); | 142 | ctrl = PWM_READ(sc, PWM0_CTRL); | |
143 | period = PWM_READ(sc, PWM0_PERIOD_HPR); | 143 | period = PWM_READ(sc, PWM0_PERIOD_HPR); | |
144 | duty = PWM_READ(sc, PWM0_DUTY_LPR); | 144 | duty = PWM_READ(sc, PWM0_DUTY_LPR); | |
145 | 145 | |||
146 | if (ctrl & CTRL_CLK_SEL) { | 146 | if (ctrl & CTRL_CLK_SEL) { | |
147 | div = __SHIFTOUT(ctrl, CTRL_SCALE) * 2; | 147 | div = __SHIFTOUT(ctrl, CTRL_SCALE) * 2; | |
148 | if (div == 0) | 148 | if (div == 0) | |
149 | div = 512; | 149 | div = 512; | |
150 | } else { | 150 | } else { | |
151 | div = 1; | 151 | div = 1; | |
152 | } | 152 | } | |
153 | div /= (1 << __SHIFTOUT(ctrl, CTRL_PRESCALE)); | 153 | div /= (1 << __SHIFTOUT(ctrl, CTRL_PRESCALE)); | |
154 | 154 | |||
155 | const uint64_t rate = sc->sc_clkfreq / div; | 155 | const uint64_t rate = sc->sc_clkfreq / div; | |
156 | 156 | |||
157 | conf->polarity = (ctrl & CTRL_DUTY_POL) ? PWM_ACTIVE_HIGH : PWM_ACTIVE_LOW; | 157 | conf->polarity = (ctrl & CTRL_DUTY_POL) ? PWM_ACTIVE_HIGH : PWM_ACTIVE_LOW; | |
158 | conf->period = (u_int)(((uint64_t)period * 1000000000) / rate); | 158 | conf->period = (u_int)(((uint64_t)period * 1000000000) / rate); | |
159 | conf->duty_cycle = (u_int)(((uint64_t)duty * 1000000000) / rate); | 159 | conf->duty_cycle = (u_int)(((uint64_t)duty * 1000000000) / rate); | |
160 | #else | 160 | #else | |
161 | *conf = sc->sc_conf; | 161 | *conf = sc->sc_conf; | |
162 | #endif | 162 | #endif | |
163 | 163 | |||
164 | return 0; | 164 | return 0; | |
165 | } | 165 | } | |
166 | 166 | |||
167 | static int | 167 | static int | |
168 | rk_pwm_set_config(pwm_tag_t pwm, const struct pwm_config *conf) | 168 | rk_pwm_set_config(pwm_tag_t pwm, const struct pwm_config *conf) | |
169 | { | 169 | { | |
170 | struct rk_pwm_softc * const sc = device_private(pwm->pwm_dev); | 170 | struct rk_pwm_softc * const sc = device_private(pwm->pwm_dev); | |
171 | uint32_t ctrl; | 171 | uint32_t ctrl; | |
172 | 172 | |||
173 | const uint64_t rate = sc->sc_clkfreq; | 173 | const uint64_t rate = sc->sc_clkfreq; | |
174 | const uint32_t period = (u_int)((conf->period * rate) / 1000000000); | 174 | const uint32_t period = (u_int)((conf->period * rate) / 1000000000); | |
175 | const uint32_t duty = (u_int)((conf->duty_cycle * rate) / 1000000000); | 175 | const uint32_t duty = (u_int)((conf->duty_cycle * rate) / 1000000000); | |
176 | 176 | |||
177 | /* Preserve PWM_EN flag */ | 177 | /* Preserve PWM_EN flag */ | |
178 | ctrl = PWM_READ(sc, PWM0_CTRL) & CTRL_PWM_EN; | 178 | ctrl = PWM_READ(sc, PWM0_CTRL) & CTRL_PWM_EN; | |
179 | 179 | |||
180 | ctrl |= __SHIFTIN(CTRL_PWM_MODE_CONTINUOUS, CTRL_PWM_MODE); | 180 | ctrl |= __SHIFTIN(CTRL_PWM_MODE_CONTINUOUS, CTRL_PWM_MODE); | |
181 | if (conf->polarity == PWM_ACTIVE_HIGH) | 181 | if (conf->polarity == PWM_ACTIVE_HIGH) | |
182 | ctrl |= CTRL_DUTY_POL; | 182 | ctrl |= CTRL_DUTY_POL; | |
183 | else | 183 | else | |
184 | ctrl |= CTRL_INACTIVE_POL; | 184 | ctrl |= CTRL_INACTIVE_POL; | |
185 | 185 | |||
186 | PWM_WRITE(sc, PWM0_CTRL, 0); | 186 | PWM_WRITE(sc, PWM0_CTRL, 0); | |
187 | PWM_WRITE(sc, PWM0_PERIOD_HPR, period); | 187 | PWM_WRITE(sc, PWM0_PERIOD_HPR, period); | |
188 | PWM_WRITE(sc, PWM0_DUTY_LPR, duty); | 188 | PWM_WRITE(sc, PWM0_DUTY_LPR, duty); | |
189 | PWM_WRITE(sc, PWM0_CTRL, ctrl); | 189 | PWM_WRITE(sc, PWM0_CTRL, ctrl); | |
190 | 190 | |||
191 | sc->sc_conf = *conf; | 191 | sc->sc_conf = *conf; | |
192 | 192 | |||
193 | return 0; | 193 | return 0; | |
194 | } | 194 | } | |
195 | 195 | |||
196 | static int | 196 | static int | |
197 | rk_pwm_match(device_t parent, cfdata_t cf, void *aux) | 197 | rk_pwm_match(device_t parent, cfdata_t cf, void *aux) | |
198 | { | 198 | { | |
199 | struct fdt_attach_args * const faa = aux; | 199 | struct fdt_attach_args * const faa = aux; | |
200 | 200 | |||
201 | return of_match_compat_data(faa->faa_phandle, compat_data); | 201 | return of_match_compat_data(faa->faa_phandle, compat_data); | |
202 | } | 202 | } | |
203 | 203 | |||
204 | static void | 204 | static void | |
205 | rk_pwm_attach(device_t parent, device_t self, void *aux) | 205 | rk_pwm_attach(device_t parent, device_t self, void *aux) | |
206 | { | 206 | { | |
207 | struct rk_pwm_softc * const sc = device_private(self); | 207 | struct rk_pwm_softc * const sc = device_private(self); | |
208 | struct fdt_attach_args * const faa = aux; | 208 | struct fdt_attach_args * const faa = aux; | |
209 | const int phandle = faa->faa_phandle; | 209 | const int phandle = faa->faa_phandle; | |
210 | struct clk *clk; | 210 | struct clk *clk; | |
211 | bus_addr_t addr; | 211 | bus_addr_t addr; | |
212 | bus_size_t size; | 212 | bus_size_t size; | |
213 | int error; | 213 | int error; | |
214 | 214 | |||
215 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | 215 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | |
216 | aprint_error(": couldn't get registers\n"); | 216 | aprint_error(": couldn't get registers\n"); | |
217 | return; | 217 | return; | |
218 | } | 218 | } | |
219 | 219 | |||
220 | clk = fdtbus_clock_get_index(phandle, 0); | 220 | clk = fdtbus_clock_get_index(phandle, 0); | |
221 | if (clk == NULL) { | 221 | if (clk == NULL) { | |
222 | aprint_error(": couldn't get clock\n"); | 222 | aprint_error(": couldn't get clock\n"); | |
223 | return; | 223 | return; | |
224 | } | 224 | } | |
225 | 225 | |||
226 | sc->sc_dev = self; | 226 | sc->sc_dev = self; | |
227 | sc->sc_clkfreq = clk_get_rate(clk); | 227 | sc->sc_clkfreq = clk_get_rate(clk); | |
228 | sc->sc_bst = faa->faa_bst; | 228 | sc->sc_bst = faa->faa_bst; | |
229 | error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); | 229 | error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); | |
230 | if (error) { | 230 | if (error) { | |
231 | aprint_error(": couldn't map %#" PRIxBUSADDR ": %d", | 231 | aprint_error(": couldn't map %#" PRIxBUSADDR ": %d", | |
232 | addr, error); | 232 | addr, error); | |
233 | return; | 233 | return; | |
234 | } | 234 | } | |
235 | 235 | |||
236 | aprint_naive("\n"); | 236 | aprint_naive("\n"); | |
237 | aprint_normal(": PWM\n"); | 237 | aprint_normal(": PWM\n"); | |
238 | 238 | |||
239 | sc->sc_pwm.pwm_enable = rk_pwm_enable; | 239 | sc->sc_pwm.pwm_enable = rk_pwm_enable; | |
240 | sc->sc_pwm.pwm_get_config = rk_pwm_get_config; | 240 | sc->sc_pwm.pwm_get_config = rk_pwm_get_config; | |
241 | sc->sc_pwm.pwm_set_config = rk_pwm_set_config; | 241 | sc->sc_pwm.pwm_set_config = rk_pwm_set_config; | |
242 | sc->sc_pwm.pwm_dev = self; | 242 | sc->sc_pwm.pwm_dev = self; | |
243 | 243 | |||
244 | fdtbus_register_pwm_controller(self, phandle, | 244 | fdtbus_register_pwm_controller(self, phandle, | |
245 | &rk_pwm_funcs); | 245 | &rk_pwm_funcs); | |
246 | } | 246 | } | |
247 | 247 | |||
248 | CFATTACH_DECL_NEW(rk_pwm, sizeof(struct rk_pwm_softc), | 248 | CFATTACH_DECL_NEW(rk_pwm, sizeof(struct rk_pwm_softc), | |
249 | rk_pwm_match, rk_pwm_attach, NULL, NULL); | 249 | rk_pwm_match, rk_pwm_attach, NULL, NULL); |
--- src/sys/arch/arm/rockchip/rk_v1crypto.c 2021/01/25 14:20:38 1.5
+++ src/sys/arch/arm/rockchip/rk_v1crypto.c 2021/01/27 02:00:02 1.6
@@ -1,386 +1,386 @@ | @@ -1,386 +1,386 @@ | |||
1 | /* $NetBSD: rk_v1crypto.c,v 1.5 2021/01/25 14:20:38 thorpej Exp $ */ | 1 | /* $NetBSD: rk_v1crypto.c,v 1.6 2021/01/27 02:00:02 thorpej Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2020 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2020 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Taylor R. Campbell. | 8 | * by Taylor R. Campbell. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * rk_v1crypto -- Rockchip crypto v1 driver | 33 | * rk_v1crypto -- Rockchip crypto v1 driver | |
34 | * | 34 | * | |
35 | * This is just the RNG for now. | 35 | * This is just the RNG for now. | |
36 | */ | 36 | */ | |
37 | 37 | |||
38 | #include <sys/cdefs.h> | 38 | #include <sys/cdefs.h> | |
39 | __KERNEL_RCSID(1, "$NetBSD: rk_v1crypto.c,v 1.5 2021/01/25 14:20:38 thorpej Exp $"); | 39 | __KERNEL_RCSID(1, "$NetBSD: rk_v1crypto.c,v 1.6 2021/01/27 02:00:02 thorpej Exp $"); | |
40 | 40 | |||
41 | #include <sys/types.h> | 41 | #include <sys/types.h> | |
42 | 42 | |||
43 | #include <sys/bus.h> | 43 | #include <sys/bus.h> | |
44 | #include <sys/device.h> | 44 | #include <sys/device.h> | |
45 | #include <sys/errno.h> | 45 | #include <sys/errno.h> | |
46 | #include <sys/mutex.h> | 46 | #include <sys/mutex.h> | |
47 | #include <sys/rndsource.h> | 47 | #include <sys/rndsource.h> | |
48 | #include <sys/sysctl.h> | 48 | #include <sys/sysctl.h> | |
49 | 49 | |||
50 | #include <dev/fdt/fdtvar.h> | 50 | #include <dev/fdt/fdtvar.h> | |
51 | 51 | |||
52 | #include <arm/rockchip/rk_v1crypto.h> | 52 | #include <arm/rockchip/rk_v1crypto.h> | |
53 | 53 | |||
54 | struct rk_v1crypto_softc { | 54 | struct rk_v1crypto_softc { | |
55 | device_t sc_dev; | 55 | device_t sc_dev; | |
56 | bus_space_tag_t sc_bst; | 56 | bus_space_tag_t sc_bst; | |
57 | bus_space_handle_t sc_bsh; | 57 | bus_space_handle_t sc_bsh; | |
58 | kmutex_t sc_lock; | 58 | kmutex_t sc_lock; | |
59 | struct krndsource sc_rndsource; | 59 | struct krndsource sc_rndsource; | |
60 | struct rk_v1crypto_sysctl { | 60 | struct rk_v1crypto_sysctl { | |
61 | struct sysctllog *cy_log; | 61 | struct sysctllog *cy_log; | |
62 | const struct sysctlnode *cy_root_node; | 62 | const struct sysctlnode *cy_root_node; | |
63 | } sc_sysctl; | 63 | } sc_sysctl; | |
64 | }; | 64 | }; | |
65 | 65 | |||
66 | static int rk_v1crypto_match(device_t, cfdata_t, void *); | 66 | static int rk_v1crypto_match(device_t, cfdata_t, void *); | |
67 | static void rk_v1crypto_attach(device_t, device_t, void *); | 67 | static void rk_v1crypto_attach(device_t, device_t, void *); | |
68 | static int rk_v1crypto_selftest(struct rk_v1crypto_softc *); | 68 | static int rk_v1crypto_selftest(struct rk_v1crypto_softc *); | |
69 | static void rk_v1crypto_rndsource_attach(struct rk_v1crypto_softc *); | 69 | static void rk_v1crypto_rndsource_attach(struct rk_v1crypto_softc *); | |
70 | static void rk_v1crypto_rng_get(size_t, void *); | 70 | static void rk_v1crypto_rng_get(size_t, void *); | |
71 | static void rk_v1crypto_sysctl_attach(struct rk_v1crypto_softc *); | 71 | static void rk_v1crypto_sysctl_attach(struct rk_v1crypto_softc *); | |
72 | static int rk_v1crypto_sysctl_rng(SYSCTLFN_ARGS); | 72 | static int rk_v1crypto_sysctl_rng(SYSCTLFN_ARGS); | |
73 | static int rk_v1crypto_rng(struct rk_v1crypto_softc *, | 73 | static int rk_v1crypto_rng(struct rk_v1crypto_softc *, | |
74 | uint32_t[static RK_V1CRYPTO_TRNG_NOUT]); | 74 | uint32_t[static RK_V1CRYPTO_TRNG_NOUT]); | |
75 | 75 | |||
76 | static uint32_t | 76 | static uint32_t | |
77 | RKC_READ(struct rk_v1crypto_softc *sc, bus_addr_t reg) | 77 | RKC_READ(struct rk_v1crypto_softc *sc, bus_addr_t reg) | |
78 | { | 78 | { | |
79 | return bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg); | 79 | return bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg); | |
80 | } | 80 | } | |
81 | 81 | |||
82 | static void | 82 | static void | |
83 | RKC_WRITE(struct rk_v1crypto_softc *sc, bus_addr_t reg, uint32_t v) | 83 | RKC_WRITE(struct rk_v1crypto_softc *sc, bus_addr_t reg, uint32_t v) | |
84 | { | 84 | { | |
85 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, v); | 85 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, v); | |
86 | } | 86 | } | |
87 | 87 | |||
88 | static inline void | 88 | static inline void | |
89 | RKC_CTRL(struct rk_v1crypto_softc *sc, uint16_t m, uint16_t v) | 89 | RKC_CTRL(struct rk_v1crypto_softc *sc, uint16_t m, uint16_t v) | |
90 | { | 90 | { | |
91 | uint32_t c = 0; | 91 | uint32_t c = 0; | |
92 | 92 | |||
93 | c |= __SHIFTIN(m, RK_V1CRYPTO_CTRL_MASK); | 93 | c |= __SHIFTIN(m, RK_V1CRYPTO_CTRL_MASK); | |
94 | c |= __SHIFTIN(v, m); | 94 | c |= __SHIFTIN(v, m); | |
95 | RKC_WRITE(sc, RK_V1CRYPTO_CTRL, c); | 95 | RKC_WRITE(sc, RK_V1CRYPTO_CTRL, c); | |
96 | } | 96 | } | |
97 | 97 | |||
98 | CFATTACH_DECL_NEW(rk_v1crypto, sizeof(struct rk_v1crypto_softc), | 98 | CFATTACH_DECL_NEW(rk_v1crypto, sizeof(struct rk_v1crypto_softc), | |
99 | rk_v1crypto_match, rk_v1crypto_attach, NULL, NULL); | 99 | rk_v1crypto_match, rk_v1crypto_attach, NULL, NULL); | |
100 | 100 | |||
101 | static const struct device_compatible_entry compat_data[] = { | 101 | static const struct device_compatible_entry compat_data[] = { | |
102 | { .compat = "rockchip,rk3288-crypto" }, | 102 | { .compat = "rockchip,rk3288-crypto" }, | |
103 | { } | 103 | DEVICE_COMPAT_EOL | |
104 | }; | 104 | }; | |
105 | 105 | |||
106 | static int | 106 | static int | |
107 | rk_v1crypto_match(device_t parent, cfdata_t cf, void *aux) | 107 | rk_v1crypto_match(device_t parent, cfdata_t cf, void *aux) | |
108 | { | 108 | { | |
109 | const struct fdt_attach_args *const faa = aux; | 109 | const struct fdt_attach_args *const faa = aux; | |
110 | 110 | |||
111 | return of_match_compat_data(faa->faa_phandle, compat_data); | 111 | return of_match_compat_data(faa->faa_phandle, compat_data); | |
112 | } | 112 | } | |
113 | 113 | |||
114 | static void | 114 | static void | |
115 | rk_v1crypto_attach(device_t parent, device_t self, void *aux) | 115 | rk_v1crypto_attach(device_t parent, device_t self, void *aux) | |
116 | { | 116 | { | |
117 | static const char *const clks[] = {"aclk", "hclk", "sclk", "apb_pclk"}; | 117 | static const char *const clks[] = {"aclk", "hclk", "sclk", "apb_pclk"}; | |
118 | struct rk_v1crypto_softc *const sc = device_private(self); | 118 | struct rk_v1crypto_softc *const sc = device_private(self); | |
119 | const struct fdt_attach_args *const faa = aux; | 119 | const struct fdt_attach_args *const faa = aux; | |
120 | bus_addr_t addr; | 120 | bus_addr_t addr; | |
121 | bus_size_t size; | 121 | bus_size_t size; | |
122 | const int phandle = faa->faa_phandle; | 122 | const int phandle = faa->faa_phandle; | |
123 | struct fdtbus_reset *rst; | 123 | struct fdtbus_reset *rst; | |
124 | unsigned i; | 124 | unsigned i; | |
125 | uint32_t ctrl; | 125 | uint32_t ctrl; | |
126 | 126 | |||
127 | fdtbus_clock_assign(phandle); | 127 | fdtbus_clock_assign(phandle); | |
128 | 128 | |||
129 | sc->sc_dev = self; | 129 | sc->sc_dev = self; | |
130 | sc->sc_bst = faa->faa_bst; | 130 | sc->sc_bst = faa->faa_bst; | |
131 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); | 131 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); | |
132 | 132 | |||
133 | /* Get and map device registers. */ | 133 | /* Get and map device registers. */ | |
134 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | 134 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | |
135 | aprint_error(": couldn't get registers\n"); | 135 | aprint_error(": couldn't get registers\n"); | |
136 | return; | 136 | return; | |
137 | } | 137 | } | |
138 | if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { | 138 | if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { | |
139 | aprint_error(": couldn't map registers\n"); | 139 | aprint_error(": couldn't map registers\n"); | |
140 | return; | 140 | return; | |
141 | } | 141 | } | |
142 | 142 | |||
143 | /* Enable the clocks. */ | 143 | /* Enable the clocks. */ | |
144 | for (i = 0; i < __arraycount(clks); i++) { | 144 | for (i = 0; i < __arraycount(clks); i++) { | |
145 | if (fdtbus_clock_enable(phandle, clks[i], true) != 0) { | 145 | if (fdtbus_clock_enable(phandle, clks[i], true) != 0) { | |
146 | aprint_error(": couldn't enable %s clock\n", clks[i]); | 146 | aprint_error(": couldn't enable %s clock\n", clks[i]); | |
147 | return; | 147 | return; | |
148 | } | 148 | } | |
149 | } | 149 | } | |
150 | 150 | |||
151 | /* Get a reset handle if we need and try to deassert it. */ | 151 | /* Get a reset handle if we need and try to deassert it. */ | |
152 | if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL) { | 152 | if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL) { | |
153 | if (fdtbus_reset_deassert(rst) != 0) { | 153 | if (fdtbus_reset_deassert(rst) != 0) { | |
154 | aprint_error(": couldn't de-assert reset\n"); | 154 | aprint_error(": couldn't de-assert reset\n"); | |
155 | return; | 155 | return; | |
156 | } | 156 | } | |
157 | } | 157 | } | |
158 | 158 | |||
159 | aprint_naive("\n"); | 159 | aprint_naive("\n"); | |
160 | aprint_normal(": Crypto v1\n"); | 160 | aprint_normal(": Crypto v1\n"); | |
161 | 161 | |||
162 | /* | 162 | /* | |
163 | * Enable ring oscillator to start gathering entropy, and set | 163 | * Enable ring oscillator to start gathering entropy, and set | |
164 | * up the crypto clock to sample it once every 100 cycles. | 164 | * up the crypto clock to sample it once every 100 cycles. | |
165 | * | 165 | * | |
166 | * The ring oscillator can run even when the clock is gated or | 166 | * The ring oscillator can run even when the clock is gated or | |
167 | * flush is asserted, and the longer we run it, the less it | 167 | * flush is asserted, and the longer we run it, the less it | |
168 | * will be synchronized with the main clock owing to jitter | 168 | * will be synchronized with the main clock owing to jitter | |
169 | * ideally from unpredictable thermal noise. | 169 | * ideally from unpredictable thermal noise. | |
170 | */ | 170 | */ | |
171 | ctrl = RK_V1CRYPTO_TRNG_CTRL_OSC_ENABLE; | 171 | ctrl = RK_V1CRYPTO_TRNG_CTRL_OSC_ENABLE; | |
172 | ctrl |= __SHIFTIN(100, RK_V1CRYPTO_TRNG_CTRL_CYCLES); | 172 | ctrl |= __SHIFTIN(100, RK_V1CRYPTO_TRNG_CTRL_CYCLES); | |
173 | RKC_WRITE(sc, RK_V1CRYPTO_TRNG_CTRL, ctrl); | 173 | RKC_WRITE(sc, RK_V1CRYPTO_TRNG_CTRL, ctrl); | |
174 | 174 | |||
175 | if (rk_v1crypto_selftest(sc)) | 175 | if (rk_v1crypto_selftest(sc)) | |
176 | return; | 176 | return; | |
177 | rk_v1crypto_rndsource_attach(sc); | 177 | rk_v1crypto_rndsource_attach(sc); | |
178 | rk_v1crypto_sysctl_attach(sc); | 178 | rk_v1crypto_sysctl_attach(sc); | |
179 | } | 179 | } | |
180 | 180 | |||
181 | static int | 181 | static int | |
182 | rk_v1crypto_selftest(struct rk_v1crypto_softc *sc) | 182 | rk_v1crypto_selftest(struct rk_v1crypto_softc *sc) | |
183 | { | 183 | { | |
184 | static const uint32_t key[4] = {0}; | 184 | static const uint32_t key[4] = {0}; | |
185 | static const uint32_t input[4] = {0}; | 185 | static const uint32_t input[4] = {0}; | |
186 | static const uint32_t expected[4] = { | 186 | static const uint32_t expected[4] = { | |
187 | 0x66e94bd4, 0xef8a2c3b, 0x884cfa59, 0xca342b2e, | 187 | 0x66e94bd4, 0xef8a2c3b, 0x884cfa59, 0xca342b2e, | |
188 | }; | 188 | }; | |
189 | uint32_t output[4]; | 189 | uint32_t output[4]; | |
190 | uint32_t ctrl; | 190 | uint32_t ctrl; | |
191 | unsigned i, timo; | 191 | unsigned i, timo; | |
192 | 192 | |||
193 | /* Program the key and input block. */ | 193 | /* Program the key and input block. */ | |
194 | for (i = 0; i < 4; i++) | 194 | for (i = 0; i < 4; i++) | |
195 | RKC_WRITE(sc, RK_V1CRYPTO_AES_DIN(i), key[i]); | 195 | RKC_WRITE(sc, RK_V1CRYPTO_AES_DIN(i), key[i]); | |
196 | for (i = 0; i < 4; i++) | 196 | for (i = 0; i < 4; i++) | |
197 | RKC_WRITE(sc, RK_V1CRYPTO_AES_DIN(i), input[i]); | 197 | RKC_WRITE(sc, RK_V1CRYPTO_AES_DIN(i), input[i]); | |
198 | 198 | |||
199 | /* | 199 | /* | |
200 | * Set up the AES unit to do AES-128 `ECB' (i.e., just the raw | 200 | * Set up the AES unit to do AES-128 `ECB' (i.e., just the raw | |
201 | * AES permutation) in the encryption direction. | 201 | * AES permutation) in the encryption direction. | |
202 | */ | 202 | */ | |
203 | ctrl = 0; | 203 | ctrl = 0; | |
204 | ctrl |= RK_V1CRYPTO_AES_CTRL_KEYCHANGE; | 204 | ctrl |= RK_V1CRYPTO_AES_CTRL_KEYCHANGE; | |
205 | ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_MODE_ECB, | 205 | ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_MODE_ECB, | |
206 | RK_V1CRYPTO_AES_CTRL_MODE); | 206 | RK_V1CRYPTO_AES_CTRL_MODE); | |
207 | ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_KEYSIZE_128, | 207 | ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_KEYSIZE_128, | |
208 | RK_V1CRYPTO_AES_CTRL_KEYSIZE); | 208 | RK_V1CRYPTO_AES_CTRL_KEYSIZE); | |
209 | ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_DIR_ENC, | 209 | ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_DIR_ENC, | |
210 | RK_V1CRYPTO_AES_CTRL_DIR); | 210 | RK_V1CRYPTO_AES_CTRL_DIR); | |
211 | RKC_WRITE(sc, RK_V1CRYPTO_AES_CTRL, ctrl); | 211 | RKC_WRITE(sc, RK_V1CRYPTO_AES_CTRL, ctrl); | |
212 | 212 | |||
213 | /* Kick it off. */ | 213 | /* Kick it off. */ | |
214 | RKC_CTRL(sc, RK_V1CRYPTO_CTRL_AES_START, 1); | 214 | RKC_CTRL(sc, RK_V1CRYPTO_CTRL_AES_START, 1); | |
215 | 215 | |||
216 | /* Wait up to 1ms for it to complete. */ | 216 | /* Wait up to 1ms for it to complete. */ | |
217 | timo = 1000; | 217 | timo = 1000; | |
218 | while (RKC_READ(sc, RK_V1CRYPTO_CTRL) & RK_V1CRYPTO_CTRL_AES_START) { | 218 | while (RKC_READ(sc, RK_V1CRYPTO_CTRL) & RK_V1CRYPTO_CTRL_AES_START) { | |
219 | if (--timo == 0) { | 219 | if (--timo == 0) { | |
220 | device_printf(sc->sc_dev, "AES self-test timed out\n"); | 220 | device_printf(sc->sc_dev, "AES self-test timed out\n"); | |
221 | return -1; | 221 | return -1; | |
222 | } | 222 | } | |
223 | DELAY(1); | 223 | DELAY(1); | |
224 | } | 224 | } | |
225 | 225 | |||
226 | /* Read the output. */ | 226 | /* Read the output. */ | |
227 | for (i = 0; i < 4; i++) | 227 | for (i = 0; i < 4; i++) | |
228 | output[i] = RKC_READ(sc, RK_V1CRYPTO_AES_DOUT(i)); | 228 | output[i] = RKC_READ(sc, RK_V1CRYPTO_AES_DOUT(i)); | |
229 | 229 | |||
230 | /* Verify the output. */ | 230 | /* Verify the output. */ | |
231 | for (i = 0; i < 4; i++) { | 231 | for (i = 0; i < 4; i++) { | |
232 | if (output[i] != expected[i]) { | 232 | if (output[i] != expected[i]) { | |
233 | device_printf(sc->sc_dev, "AES self-test failed\n"); | 233 | device_printf(sc->sc_dev, "AES self-test failed\n"); | |
234 | return -1; | 234 | return -1; | |
235 | } | 235 | } | |
236 | } | 236 | } | |
237 | 237 | |||
238 | /* Success! */ | 238 | /* Success! */ | |
239 | return 0; | 239 | return 0; | |
240 | } | 240 | } | |
241 | 241 | |||
242 | static void | 242 | static void | |
243 | rk_v1crypto_rndsource_attach(struct rk_v1crypto_softc *sc) | 243 | rk_v1crypto_rndsource_attach(struct rk_v1crypto_softc *sc) | |
244 | { | 244 | { | |
245 | device_t self = sc->sc_dev; | 245 | device_t self = sc->sc_dev; | |
246 | 246 | |||
247 | rndsource_setcb(&sc->sc_rndsource, rk_v1crypto_rng_get, sc); | 247 | rndsource_setcb(&sc->sc_rndsource, rk_v1crypto_rng_get, sc); | |
248 | rnd_attach_source(&sc->sc_rndsource, device_xname(self), | 248 | rnd_attach_source(&sc->sc_rndsource, device_xname(self), | |
249 | RND_TYPE_RNG, RND_FLAG_DEFAULT|RND_FLAG_HASCB); | 249 | RND_TYPE_RNG, RND_FLAG_DEFAULT|RND_FLAG_HASCB); | |
250 | } | 250 | } | |
251 | 251 | |||
252 | static void | 252 | static void | |
253 | rk_v1crypto_rng_get(size_t nbytes, void *cookie) | 253 | rk_v1crypto_rng_get(size_t nbytes, void *cookie) | |
254 | { | 254 | { | |
255 | struct rk_v1crypto_softc *sc = cookie; | 255 | struct rk_v1crypto_softc *sc = cookie; | |
256 | device_t self = sc->sc_dev; | 256 | device_t self = sc->sc_dev; | |
257 | uint32_t buf[RK_V1CRYPTO_TRNG_NOUT]; | 257 | uint32_t buf[RK_V1CRYPTO_TRNG_NOUT]; | |
258 | uint32_t entropybits = NBBY*sizeof(buf)/2; /* be conservative */ | 258 | uint32_t entropybits = NBBY*sizeof(buf)/2; /* be conservative */ | |
259 | unsigned n = RK_V1CRYPTO_TRNG_NOUT; | 259 | unsigned n = RK_V1CRYPTO_TRNG_NOUT; | |
260 | int error; | 260 | int error; | |
261 | size_t nbits = NBBY*nbytes; | 261 | size_t nbits = NBBY*nbytes; | |
262 | 262 | |||
263 | while (nbits) { | 263 | while (nbits) { | |
264 | CTASSERT((RK_V1CRYPTO_TRNG_NOUT % 2) == 0); | 264 | CTASSERT((RK_V1CRYPTO_TRNG_NOUT % 2) == 0); | |
265 | 265 | |||
266 | error = rk_v1crypto_rng(sc, buf); | 266 | error = rk_v1crypto_rng(sc, buf); | |
267 | if (error) { | 267 | if (error) { | |
268 | device_printf(self, "timed out\n"); | 268 | device_printf(self, "timed out\n"); | |
269 | break; | 269 | break; | |
270 | } | 270 | } | |
271 | if (consttime_memequal(buf, buf + n/2, n/2)) { | 271 | if (consttime_memequal(buf, buf + n/2, n/2)) { | |
272 | device_printf(self, "failed repeated output test\n"); | 272 | device_printf(self, "failed repeated output test\n"); | |
273 | break; | 273 | break; | |
274 | } | 274 | } | |
275 | rnd_add_data_sync(&sc->sc_rndsource, buf, sizeof buf, | 275 | rnd_add_data_sync(&sc->sc_rndsource, buf, sizeof buf, | |
276 | entropybits); | 276 | entropybits); | |
277 | nbits -= MIN(nbits, MAX(1, entropybits)); | 277 | nbits -= MIN(nbits, MAX(1, entropybits)); | |
278 | } | 278 | } | |
279 | explicit_memset(buf, 0, sizeof buf); | 279 | explicit_memset(buf, 0, sizeof buf); | |
280 | } | 280 | } | |
281 | 281 | |||
282 | static void | 282 | static void | |
283 | rk_v1crypto_sysctl_attach(struct rk_v1crypto_softc *sc) | 283 | rk_v1crypto_sysctl_attach(struct rk_v1crypto_softc *sc) | |
284 | { | 284 | { | |
285 | device_t self = sc->sc_dev; | 285 | device_t self = sc->sc_dev; | |
286 | struct rk_v1crypto_sysctl *cy = &sc->sc_sysctl; | 286 | struct rk_v1crypto_sysctl *cy = &sc->sc_sysctl; | |
287 | int error; | 287 | int error; | |
288 | 288 | |||
289 | /* hw.rkv1cryptoN (node) */ | 289 | /* hw.rkv1cryptoN (node) */ | |
290 | error = sysctl_createv(&cy->cy_log, 0, NULL, &cy->cy_root_node, | 290 | error = sysctl_createv(&cy->cy_log, 0, NULL, &cy->cy_root_node, | |
291 | CTLFLAG_PERMANENT, CTLTYPE_NODE, device_xname(self), | 291 | CTLFLAG_PERMANENT, CTLTYPE_NODE, device_xname(self), | |
292 | SYSCTL_DESCR("rk crypto v1 engine knobs"), | 292 | SYSCTL_DESCR("rk crypto v1 engine knobs"), | |
293 | NULL, 0, NULL, 0, | 293 | NULL, 0, NULL, 0, | |
294 | CTL_HW, CTL_CREATE, CTL_EOL); | 294 | CTL_HW, CTL_CREATE, CTL_EOL); | |
295 | if (error) { | 295 | if (error) { | |
296 | aprint_error_dev(self, | 296 | aprint_error_dev(self, | |
297 | "failed to set up sysctl hw.%s: %d\n", | 297 | "failed to set up sysctl hw.%s: %d\n", | |
298 | device_xname(self), error); | 298 | device_xname(self), error); | |
299 | return; | 299 | return; | |
300 | } | 300 | } | |
301 | 301 | |||
302 | /* hw.rkv1cryptoN.rng (`struct', 32-byte array) */ | 302 | /* hw.rkv1cryptoN.rng (`struct', 32-byte array) */ | |
303 | sysctl_createv(&cy->cy_log, 0, &cy->cy_root_node, NULL, | 303 | sysctl_createv(&cy->cy_log, 0, &cy->cy_root_node, NULL, | |
304 | CTLFLAG_PERMANENT|CTLFLAG_READONLY|CTLFLAG_PRIVATE, CTLTYPE_STRUCT, | 304 | CTLFLAG_PERMANENT|CTLFLAG_READONLY|CTLFLAG_PRIVATE, CTLTYPE_STRUCT, | |
305 | "rng", SYSCTL_DESCR("Read up to 32 bytes out of the TRNG"), | 305 | "rng", SYSCTL_DESCR("Read up to 32 bytes out of the TRNG"), | |
306 | &rk_v1crypto_sysctl_rng, 0, sc, 0, CTL_CREATE, CTL_EOL); | 306 | &rk_v1crypto_sysctl_rng, 0, sc, 0, CTL_CREATE, CTL_EOL); | |
307 | if (error) { | 307 | if (error) { | |
308 | aprint_error_dev(self, | 308 | aprint_error_dev(self, | |
309 | "failed to set up sysctl hw.%s.rng: %d\n", | 309 | "failed to set up sysctl hw.%s.rng: %d\n", | |
310 | device_xname(self), error); | 310 | device_xname(self), error); | |
311 | return; | 311 | return; | |
312 | } | 312 | } | |
313 | } | 313 | } | |
314 | 314 | |||
315 | static int | 315 | static int | |
316 | rk_v1crypto_sysctl_rng(SYSCTLFN_ARGS) | 316 | rk_v1crypto_sysctl_rng(SYSCTLFN_ARGS) | |
317 | { | 317 | { | |
318 | uint32_t buf[RK_V1CRYPTO_TRNG_NOUT]; | 318 | uint32_t buf[RK_V1CRYPTO_TRNG_NOUT]; | |
319 | struct sysctlnode node = *rnode; | 319 | struct sysctlnode node = *rnode; | |
320 | struct rk_v1crypto_softc *sc = node.sysctl_data; | 320 | struct rk_v1crypto_softc *sc = node.sysctl_data; | |
321 | size_t size; | 321 | size_t size; | |
322 | int error; | 322 | int error; | |
323 | 323 | |||
324 | /* If oldp == NULL, the caller wants to learn the size. */ | 324 | /* If oldp == NULL, the caller wants to learn the size. */ | |
325 | if (oldp == NULL) { | 325 | if (oldp == NULL) { | |
326 | *oldlenp = sizeof buf; | 326 | *oldlenp = sizeof buf; | |
327 | return 0; | 327 | return 0; | |
328 | } | 328 | } | |
329 | 329 | |||
330 | /* Verify the output buffer size is reasonable. */ | 330 | /* Verify the output buffer size is reasonable. */ | |
331 | size = *oldlenp; | 331 | size = *oldlenp; | |
332 | if (size > sizeof buf) /* size_t, so never negative */ | 332 | if (size > sizeof buf) /* size_t, so never negative */ | |
333 | return E2BIG; | 333 | return E2BIG; | |
334 | if (size == 0) | 334 | if (size == 0) | |
335 | return 0; /* nothing to do */ | 335 | return 0; /* nothing to do */ | |
336 | 336 | |||
337 | /* Generate data. */ | 337 | /* Generate data. */ | |
338 | error = rk_v1crypto_rng(sc, buf); | 338 | error = rk_v1crypto_rng(sc, buf); | |
339 | if (error) | 339 | if (error) | |
340 | return error; | 340 | return error; | |
341 | 341 | |||
342 | /* Copy out the data. */ | 342 | /* Copy out the data. */ | |
343 | node.sysctl_data = buf; | 343 | node.sysctl_data = buf; | |
344 | node.sysctl_size = size; | 344 | node.sysctl_size = size; | |
345 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); | 345 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); | |
346 | 346 | |||
347 | /* Clear the buffer. */ | 347 | /* Clear the buffer. */ | |
348 | explicit_memset(buf, 0, sizeof buf); | 348 | explicit_memset(buf, 0, sizeof buf); | |
349 | 349 | |||
350 | /* Return the sysctl_lookup error, if any. */ | 350 | /* Return the sysctl_lookup error, if any. */ | |
351 | return error; | 351 | return error; | |
352 | } | 352 | } | |
353 | 353 | |||
354 | static int | 354 | static int | |
355 | rk_v1crypto_rng(struct rk_v1crypto_softc *sc, | 355 | rk_v1crypto_rng(struct rk_v1crypto_softc *sc, | |
356 | uint32_t buf[static RK_V1CRYPTO_TRNG_NOUT]) | 356 | uint32_t buf[static RK_V1CRYPTO_TRNG_NOUT]) | |
357 | { | 357 | { | |
358 | unsigned i, timo; | 358 | unsigned i, timo; | |
359 | int error; | 359 | int error; | |
360 | 360 | |||
361 | /* Acquire lock to serialize access to TRNG. */ | 361 | /* Acquire lock to serialize access to TRNG. */ | |
362 | mutex_enter(&sc->sc_lock); | 362 | mutex_enter(&sc->sc_lock); | |
363 | 363 | |||
364 | /* | 364 | /* | |
365 | * Query TRNG and wait up to 1ms for it to post. Empirically, | 365 | * Query TRNG and wait up to 1ms for it to post. Empirically, | |
366 | * this takes around 120us. | 366 | * this takes around 120us. | |
367 | */ | 367 | */ | |
368 | RKC_CTRL(sc, RK_V1CRYPTO_CTRL_TRNG_START, 1); | 368 | RKC_CTRL(sc, RK_V1CRYPTO_CTRL_TRNG_START, 1); | |
369 | timo = 1000; | 369 | timo = 1000; | |
370 | while (RKC_READ(sc, RK_V1CRYPTO_CTRL) & RK_V1CRYPTO_CTRL_TRNG_START) { | 370 | while (RKC_READ(sc, RK_V1CRYPTO_CTRL) & RK_V1CRYPTO_CTRL_TRNG_START) { | |
371 | if (--timo == 0) { | 371 | if (--timo == 0) { | |
372 | error = ETIMEDOUT; | 372 | error = ETIMEDOUT; | |
373 | goto out; | 373 | goto out; | |
374 | } | 374 | } | |
375 | DELAY(1); | 375 | DELAY(1); | |
376 | } | 376 | } | |
377 | 377 | |||
378 | /* Read out the data. */ | 378 | /* Read out the data. */ | |
379 | for (i = 0; i < RK_V1CRYPTO_TRNG_NOUT; i++) | 379 | for (i = 0; i < RK_V1CRYPTO_TRNG_NOUT; i++) | |
380 | buf[i] = RKC_READ(sc, RK_V1CRYPTO_TRNG_DOUT(i)); | 380 | buf[i] = RKC_READ(sc, RK_V1CRYPTO_TRNG_DOUT(i)); | |
381 | 381 | |||
382 | /* Success! */ | 382 | /* Success! */ | |
383 | error = 0; | 383 | error = 0; | |
384 | out: mutex_exit(&sc->sc_lock); | 384 | out: mutex_exit(&sc->sc_lock); | |
385 | return error; | 385 | return error; | |
386 | } | 386 | } |
--- src/sys/arch/arm/rockchip/rk_tsadc.c 2021/01/25 14:20:38 1.10
+++ src/sys/arch/arm/rockchip/rk_tsadc.c 2021/01/27 02:00:02 1.11
@@ -1,894 +1,894 @@ | @@ -1,894 +1,894 @@ | |||
1 | /* $NetBSD: rk_tsadc.c,v 1.10 2021/01/25 14:20:38 thorpej Exp $ */ | 1 | /* $NetBSD: rk_tsadc.c,v 1.11 2021/01/27 02:00:02 thorpej Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2019 Matthew R. Green | 4 | * Copyright (c) 2019 Matthew R. Green | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. The name of the author may not be used to endorse or promote products | 15 | * 3. The name of the author may not be used to endorse or promote products | |
16 | * derived from this software without specific prior written permission. | 16 | * derived from this software without specific prior written permission. | |
17 | * | 17 | * | |
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
23 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 23 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
28 | * SUCH DAMAGE. | 28 | * SUCH DAMAGE. | |
29 | */ | 29 | */ | |
30 | 30 | |||
31 | #include <sys/cdefs.h> | 31 | #include <sys/cdefs.h> | |
32 | 32 | |||
33 | __KERNEL_RCSID(0, "$NetBSD: rk_tsadc.c,v 1.10 2021/01/25 14:20:38 thorpej Exp $"); | 33 | __KERNEL_RCSID(0, "$NetBSD: rk_tsadc.c,v 1.11 2021/01/27 02:00:02 thorpej Exp $"); | |
34 | 34 | |||
35 | /* | 35 | /* | |
36 | * Driver for the TSADC temperature sensor monitor in RK3328 and RK3399. | 36 | * Driver for the TSADC temperature sensor monitor in RK3328 and RK3399. | |
37 | * | 37 | * | |
38 | * TODO: | 38 | * TODO: | |
39 | * - handle setting various temp values | 39 | * - handle setting various temp values | |
40 | * - handle DT trips/temp value defaults | 40 | * - handle DT trips/temp value defaults | |
41 | * - interrupts aren't triggered (test by lowering warn/crit values), and | 41 | * - interrupts aren't triggered (test by lowering warn/crit values), and | |
42 | * once they work, make the interrupt do something | 42 | * once they work, make the interrupt do something | |
43 | */ | 43 | */ | |
44 | 44 | |||
45 | #include <sys/param.h> | 45 | #include <sys/param.h> | |
46 | #include <sys/bus.h> | 46 | #include <sys/bus.h> | |
47 | #include <sys/device.h> | 47 | #include <sys/device.h> | |
48 | #include <sys/intr.h> | 48 | #include <sys/intr.h> | |
49 | #include <sys/systm.h> | 49 | #include <sys/systm.h> | |
50 | #include <sys/time.h> | 50 | #include <sys/time.h> | |
51 | #include <sys/kmem.h> | 51 | #include <sys/kmem.h> | |
52 | 52 | |||
53 | #include <dev/fdt/fdtvar.h> | 53 | #include <dev/fdt/fdtvar.h> | |
54 | #include <dev/fdt/syscon.h> | 54 | #include <dev/fdt/syscon.h> | |
55 | 55 | |||
56 | #include <dev/sysmon/sysmonvar.h> | 56 | #include <dev/sysmon/sysmonvar.h> | |
57 | 57 | |||
58 | #ifdef RKTSADC_DEBUG | 58 | #ifdef RKTSADC_DEBUG | |
59 | #define DPRINTF(fmt, ...) \ | 59 | #define DPRINTF(fmt, ...) \ | |
60 | printf("%s:%d: " fmt "\n", __func__, __LINE__, ## __VA_ARGS__) | 60 | printf("%s:%d: " fmt "\n", __func__, __LINE__, ## __VA_ARGS__) | |
61 | #else | 61 | #else | |
62 | #define DPRINTF(fmt, ...) | 62 | #define DPRINTF(fmt, ...) | |
63 | #endif | 63 | #endif | |
64 | 64 | |||
65 | /* Register definitions */ | 65 | /* Register definitions */ | |
66 | #define TSADC_USER_CON 0x00 | 66 | #define TSADC_USER_CON 0x00 | |
67 | #define TSADC_USER_CON_ADC_STATUS __BIT(12) | 67 | #define TSADC_USER_CON_ADC_STATUS __BIT(12) | |
68 | #define TSADC_USER_CON_INTER_PD_SOC __BITS(11,6) | 68 | #define TSADC_USER_CON_INTER_PD_SOC __BITS(11,6) | |
69 | #define TSADC_USER_CON_START __BIT(5) | 69 | #define TSADC_USER_CON_START __BIT(5) | |
70 | #define TSADC_USER_CON_START_MODE __BIT(4) | 70 | #define TSADC_USER_CON_START_MODE __BIT(4) | |
71 | #define TSADC_USER_CON_ADC_POWER_CTRL __BIT(3) | 71 | #define TSADC_USER_CON_ADC_POWER_CTRL __BIT(3) | |
72 | #define TSADC_USER_CON_ADC_INPUT_SRC_SEL __BITS(2,0) | 72 | #define TSADC_USER_CON_ADC_INPUT_SRC_SEL __BITS(2,0) | |
73 | #define TSADC_AUTO_CON 0x04 | 73 | #define TSADC_AUTO_CON 0x04 | |
74 | #define TSADC_AUTO_CON_LAST_TSHUT_2CRU __BIT(25) | 74 | #define TSADC_AUTO_CON_LAST_TSHUT_2CRU __BIT(25) | |
75 | #define TSADC_AUTO_CON_LAST_TSHUT_2GPIO __BIT(24) | 75 | #define TSADC_AUTO_CON_LAST_TSHUT_2GPIO __BIT(24) | |
76 | #define TSADC_AUTO_CON_SAMPLE_DLY_SEL __BIT(17) | 76 | #define TSADC_AUTO_CON_SAMPLE_DLY_SEL __BIT(17) | |
77 | #define TSADC_AUTO_CON_AUTO_STATUS __BIT(16) | 77 | #define TSADC_AUTO_CON_AUTO_STATUS __BIT(16) | |
78 | #define TSADC_AUTO_CON_SRC1_LT_EN __BIT(13) | 78 | #define TSADC_AUTO_CON_SRC1_LT_EN __BIT(13) | |
79 | #define TSADC_AUTO_CON_SRC0_LT_EN __BIT(12) | 79 | #define TSADC_AUTO_CON_SRC0_LT_EN __BIT(12) | |
80 | #define TSADC_AUTO_CON_TSHUT_POLARITY __BIT(8) | 80 | #define TSADC_AUTO_CON_TSHUT_POLARITY __BIT(8) | |
81 | #define TSADC_AUTO_CON_SRC1_EN __BIT(5) | 81 | #define TSADC_AUTO_CON_SRC1_EN __BIT(5) | |
82 | #define TSADC_AUTO_CON_SRC0_EN __BIT(4) | 82 | #define TSADC_AUTO_CON_SRC0_EN __BIT(4) | |
83 | #define TSADC_AUTO_CON_Q_SEL __BIT(1) | 83 | #define TSADC_AUTO_CON_Q_SEL __BIT(1) | |
84 | #define TSADC_AUTO_CON_AUTO_EN __BIT(0) | 84 | #define TSADC_AUTO_CON_AUTO_EN __BIT(0) | |
85 | #define TSADC_INT_EN 0x08 | 85 | #define TSADC_INT_EN 0x08 | |
86 | #define TSADC_INT_EN_EOC_INT_EN __BIT(16) | 86 | #define TSADC_INT_EN_EOC_INT_EN __BIT(16) | |
87 | #define TSADC_INT_EN_LT_INTEN_SRC1 __BIT(13) | 87 | #define TSADC_INT_EN_LT_INTEN_SRC1 __BIT(13) | |
88 | #define TSADC_INT_EN_LT_INTEN_SRC0 __BIT(12) | 88 | #define TSADC_INT_EN_LT_INTEN_SRC0 __BIT(12) | |
89 | #define TSADC_INT_EN_TSHUT_2CRU_EN_SRC1 __BIT(9) | 89 | #define TSADC_INT_EN_TSHUT_2CRU_EN_SRC1 __BIT(9) | |
90 | #define TSADC_INT_EN_TSHUT_2CRU_EN_SRC0 __BIT(8) | 90 | #define TSADC_INT_EN_TSHUT_2CRU_EN_SRC0 __BIT(8) | |
91 | #define TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1 __BIT(5) | 91 | #define TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1 __BIT(5) | |
92 | #define TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0 __BIT(4) | 92 | #define TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0 __BIT(4) | |
93 | #define TSADC_INT_EN_HT_INTEN_SRC1 __BIT(1) | 93 | #define TSADC_INT_EN_HT_INTEN_SRC1 __BIT(1) | |
94 | #define TSADC_INT_EN_HT_INTEN_SRC0 __BIT(0) | 94 | #define TSADC_INT_EN_HT_INTEN_SRC0 __BIT(0) | |
95 | #define TSADC_INT_PD 0x0c | 95 | #define TSADC_INT_PD 0x0c | |
96 | #define TSADC_INT_PD_EOC_INT_PD __BIT(16) | 96 | #define TSADC_INT_PD_EOC_INT_PD __BIT(16) | |
97 | #define TSADC_INT_PD_LT_IRQ_SRC1 __BIT(13) | 97 | #define TSADC_INT_PD_LT_IRQ_SRC1 __BIT(13) | |
98 | #define TSADC_INT_PD_LT_IRQ_SRC0 __BIT(12) | 98 | #define TSADC_INT_PD_LT_IRQ_SRC0 __BIT(12) | |
99 | #define TSADC_INT_PD_TSHUT_O_SRC1 __BIT(5) | 99 | #define TSADC_INT_PD_TSHUT_O_SRC1 __BIT(5) | |
100 | #define TSADC_INT_PD_TSHUT_O_SRC0 __BIT(4) | 100 | #define TSADC_INT_PD_TSHUT_O_SRC0 __BIT(4) | |
101 | #define TSADC_INT_PD_HT_IRQ_SRC1 __BIT(1) | 101 | #define TSADC_INT_PD_HT_IRQ_SRC1 __BIT(1) | |
102 | #define TSADC_INT_PD_HT_IRQ_SRC0 __BIT(0) | 102 | #define TSADC_INT_PD_HT_IRQ_SRC0 __BIT(0) | |
103 | #define TSADC_DATA0 0x20 | 103 | #define TSADC_DATA0 0x20 | |
104 | #define TSADC_DATA0_ADC_DATA __BITS(11,0) | 104 | #define TSADC_DATA0_ADC_DATA __BITS(11,0) | |
105 | #define TSADC_DATA1 0x24 | 105 | #define TSADC_DATA1 0x24 | |
106 | #define TSADC_DATA1_ADC_DATA __BITS(11,0) | 106 | #define TSADC_DATA1_ADC_DATA __BITS(11,0) | |
107 | #define TSADC_COMP0_INT 0x30 | 107 | #define TSADC_COMP0_INT 0x30 | |
108 | #define TSADC_COMP0_INT_COMP_SRC0 __BITS(11,0) | 108 | #define TSADC_COMP0_INT_COMP_SRC0 __BITS(11,0) | |
109 | #define TSADC_COMP1_INT 0x34 | 109 | #define TSADC_COMP1_INT 0x34 | |
110 | #define TSADC_COMP1_INT_COMP_SRC1 __BITS(11,0) | 110 | #define TSADC_COMP1_INT_COMP_SRC1 __BITS(11,0) | |
111 | #define TSADC_COMP0_SHUT 0x40 | 111 | #define TSADC_COMP0_SHUT 0x40 | |
112 | #define TSADC_COMP0_SHUT_COMP_SRC0 __BITS(11,0) | 112 | #define TSADC_COMP0_SHUT_COMP_SRC0 __BITS(11,0) | |
113 | #define TSADC_COMP1_SHUT 0x44 | 113 | #define TSADC_COMP1_SHUT 0x44 | |
114 | #define TSADC_COMP1_SHUT_COMP_SRC1 __BITS(11,0) | 114 | #define TSADC_COMP1_SHUT_COMP_SRC1 __BITS(11,0) | |
115 | #define TSADC_HIGH_INT_DEBOUNCE 0x60 | 115 | #define TSADC_HIGH_INT_DEBOUNCE 0x60 | |
116 | #define TSADC_HIGH_INT_DEBOUNCE_TEMP __BITS(7,0) | 116 | #define TSADC_HIGH_INT_DEBOUNCE_TEMP __BITS(7,0) | |
117 | #define TSADC_HIGH_TSHUT_DEBOUNCE 0x64 | 117 | #define TSADC_HIGH_TSHUT_DEBOUNCE 0x64 | |
118 | #define TSADC_HIGH_TSHUT_DEBOUNCE_TEMP __BITS(7,0) | 118 | #define TSADC_HIGH_TSHUT_DEBOUNCE_TEMP __BITS(7,0) | |
119 | #define TSADC_AUTO_PERIOD 0x68 | 119 | #define TSADC_AUTO_PERIOD 0x68 | |
120 | #define TSADC_AUTO_PERIOD_TEMP __BITS(31,0) | 120 | #define TSADC_AUTO_PERIOD_TEMP __BITS(31,0) | |
121 | #define TSADC_AUTO_PERIOD_HT 0x6c | 121 | #define TSADC_AUTO_PERIOD_HT 0x6c | |
122 | #define TSADC_AUTO_PERIOD_HT_TEMP __BITS(31,0) | 122 | #define TSADC_AUTO_PERIOD_HT_TEMP __BITS(31,0) | |
123 | #define TSADC_COMP0_LOW_INT 0x80 | 123 | #define TSADC_COMP0_LOW_INT 0x80 | |
124 | #define TSADC_COMP0_LOW_INT_COMP_SRC0 __BITS(11,0) | 124 | #define TSADC_COMP0_LOW_INT_COMP_SRC0 __BITS(11,0) | |
125 | #define TSADC_COMP1_LOW_INT 0x84 | 125 | #define TSADC_COMP1_LOW_INT 0x84 | |
126 | #define TSADC_COMP1_LOW_INT_COMP_SRC1 __BITS(11,0) | 126 | #define TSADC_COMP1_LOW_INT_COMP_SRC1 __BITS(11,0) | |
127 | 127 | |||
128 | #define RK3328_TSADC_AUTO_PERIOD_TIME 250 /* 250ms */ | 128 | #define RK3328_TSADC_AUTO_PERIOD_TIME 250 /* 250ms */ | |
129 | #define RK3399_TSADC_AUTO_PERIOD_TIME 1875 /* 2.5ms */ | 129 | #define RK3399_TSADC_AUTO_PERIOD_TIME 1875 /* 2.5ms */ | |
130 | #define TSADC_HT_DEBOUNCE_COUNT 4 | 130 | #define TSADC_HT_DEBOUNCE_COUNT 4 | |
131 | 131 | |||
132 | /* | 132 | /* | |
133 | * All this magic is taking from the Linux rockchip_thermal driver. | 133 | * All this magic is taking from the Linux rockchip_thermal driver. | |
134 | * | 134 | * | |
135 | * VCM means "voltage common mode", but the documentation for RK3399 | 135 | * VCM means "voltage common mode", but the documentation for RK3399 | |
136 | * does not mention this and I don't know what any of this really | 136 | * does not mention this and I don't know what any of this really | |
137 | * is for. | 137 | * is for. | |
138 | */ | 138 | */ | |
139 | #define RK3399_GRF_SARADC_TESTBIT 0xe644 | 139 | #define RK3399_GRF_SARADC_TESTBIT 0xe644 | |
140 | #define RK3399_GRF_SARADC_TESTBIT_ON (0x10001 << 2) | 140 | #define RK3399_GRF_SARADC_TESTBIT_ON (0x10001 << 2) | |
141 | #define RK3399_GRF_TSADC_TESTBIT_L 0xe648 | 141 | #define RK3399_GRF_TSADC_TESTBIT_L 0xe648 | |
142 | #define RK3399_GRF_TSADC_TESTBIT_VCM_EN_L (0x10001 << 7) | 142 | #define RK3399_GRF_TSADC_TESTBIT_VCM_EN_L (0x10001 << 7) | |
143 | #define RK3399_GRF_TSADC_TESTBIT_H 0xe64c | 143 | #define RK3399_GRF_TSADC_TESTBIT_H 0xe64c | |
144 | #define RK3399_GRF_TSADC_TESTBIT_VCM_EN_H (0x10001 << 7) | 144 | #define RK3399_GRF_TSADC_TESTBIT_VCM_EN_H (0x10001 << 7) | |
145 | #define RK3399_GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) | 145 | #define RK3399_GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) | |
146 | 146 | |||
147 | #define TEMP_uC_TO_uK 273150000 | 147 | #define TEMP_uC_TO_uK 273150000 | |
148 | 148 | |||
149 | #define TSHUT_MODE_CPU 0 | 149 | #define TSHUT_MODE_CPU 0 | |
150 | #define TSHUT_MODE_GPIO 1 | 150 | #define TSHUT_MODE_GPIO 1 | |
151 | 151 | |||
152 | #define TSHUT_LOW_ACTIVE 0 | 152 | #define TSHUT_LOW_ACTIVE 0 | |
153 | #define TSHUT_HIGH_ACTIVE 1 | 153 | #define TSHUT_HIGH_ACTIVE 1 | |
154 | 154 | |||
155 | #define TSHUT_DEF_TEMP 95000 | 155 | #define TSHUT_DEF_TEMP 95000 | |
156 | 156 | |||
157 | #define TSADC_DATA_MAX 0xfff | 157 | #define TSADC_DATA_MAX 0xfff | |
158 | 158 | |||
159 | #define MAX_SENSORS 2 | 159 | #define MAX_SENSORS 2 | |
160 | 160 | |||
161 | typedef struct rk_data_array { | 161 | typedef struct rk_data_array { | |
162 | uint32_t data; /* register value */ | 162 | uint32_t data; /* register value */ | |
163 | int temp; /* micro-degC */ | 163 | int temp; /* micro-degC */ | |
164 | } rk_data_array; | 164 | } rk_data_array; | |
165 | 165 | |||
166 | struct rk_tsadc_softc; | 166 | struct rk_tsadc_softc; | |
167 | typedef struct rk_data { | 167 | typedef struct rk_data { | |
168 | const rk_data_array *rd_array; | 168 | const rk_data_array *rd_array; | |
169 | size_t rd_size; | 169 | size_t rd_size; | |
170 | void (*rd_init)(struct rk_tsadc_softc *, int, int); | 170 | void (*rd_init)(struct rk_tsadc_softc *, int, int); | |
171 | bool rd_decr; /* lower values -> higher temp */ | 171 | bool rd_decr; /* lower values -> higher temp */ | |
172 | unsigned rd_min, rd_max; | 172 | unsigned rd_min, rd_max; | |
173 | unsigned rd_auto_period; | 173 | unsigned rd_auto_period; | |
174 | unsigned rd_num_sensors; | 174 | unsigned rd_num_sensors; | |
175 | } rk_data; | 175 | } rk_data; | |
176 | 176 | |||
177 | /* Per-sensor data */ | 177 | /* Per-sensor data */ | |
178 | struct rk_tsadc_sensor { | 178 | struct rk_tsadc_sensor { | |
179 | envsys_data_t s_data; | 179 | envsys_data_t s_data; | |
180 | bool s_attached; | 180 | bool s_attached; | |
181 | /* TSADC register offsets for this sensor */ | 181 | /* TSADC register offsets for this sensor */ | |
182 | unsigned s_data_reg; | 182 | unsigned s_data_reg; | |
183 | unsigned s_comp_tshut; | 183 | unsigned s_comp_tshut; | |
184 | unsigned s_comp_int; | 184 | unsigned s_comp_int; | |
185 | /* enable bit in AUTO_CON register */ | 185 | /* enable bit in AUTO_CON register */ | |
186 | unsigned s_comp_int_en; | 186 | unsigned s_comp_int_en; | |
187 | /* warn/crit values in micro Kelvin */ | 187 | /* warn/crit values in micro Kelvin */ | |
188 | int s_warn; | 188 | int s_warn; | |
189 | int s_tshut; | 189 | int s_tshut; | |
190 | }; | 190 | }; | |
191 | 191 | |||
192 | struct rk_tsadc_softc { | 192 | struct rk_tsadc_softc { | |
193 | device_t sc_dev; | 193 | device_t sc_dev; | |
194 | int sc_phandle; | 194 | int sc_phandle; | |
195 | bus_space_tag_t sc_bst; | 195 | bus_space_tag_t sc_bst; | |
196 | bus_space_handle_t sc_bsh; | 196 | bus_space_handle_t sc_bsh; | |
197 | size_t sc_size; | 197 | size_t sc_size; | |
198 | uint32_t sc_data_mask; | 198 | uint32_t sc_data_mask; | |
199 | void *sc_ih; | 199 | void *sc_ih; | |
200 | 200 | |||
201 | struct sysmon_envsys *sc_sme; | 201 | struct sysmon_envsys *sc_sme; | |
202 | struct rk_tsadc_sensor sc_sensors[MAX_SENSORS]; | 202 | struct rk_tsadc_sensor sc_sensors[MAX_SENSORS]; | |
203 | 203 | |||
204 | struct clk *sc_clock; | 204 | struct clk *sc_clock; | |
205 | struct clk *sc_clockapb; | 205 | struct clk *sc_clockapb; | |
206 | struct fdtbus_reset *sc_reset; | 206 | struct fdtbus_reset *sc_reset; | |
207 | struct syscon *sc_syscon; | 207 | struct syscon *sc_syscon; | |
208 | 208 | |||
209 | const rk_data *sc_rd; | 209 | const rk_data *sc_rd; | |
210 | }; | 210 | }; | |
211 | 211 | |||
212 | static int rk_tsadc_match(device_t, cfdata_t, void *); | 212 | static int rk_tsadc_match(device_t, cfdata_t, void *); | |
213 | static void rk_tsadc_attach(device_t, device_t, void *); | 213 | static void rk_tsadc_attach(device_t, device_t, void *); | |
214 | static int rk_tsadc_detach(device_t, int); | 214 | static int rk_tsadc_detach(device_t, int); | |
215 | static int rk_tsadc_init_clocks(struct rk_tsadc_softc *); | 215 | static int rk_tsadc_init_clocks(struct rk_tsadc_softc *); | |
216 | static void rk_tsadc_init_counts(struct rk_tsadc_softc *); | 216 | static void rk_tsadc_init_counts(struct rk_tsadc_softc *); | |
217 | static void rk_tsadc_tshut_set(struct rk_tsadc_softc *s); | 217 | static void rk_tsadc_tshut_set(struct rk_tsadc_softc *s); | |
218 | static void rk_tsadc_init_tshut(struct rk_tsadc_softc *, int, int); | 218 | static void rk_tsadc_init_tshut(struct rk_tsadc_softc *, int, int); | |
219 | static void rk_tsadc_init_rk3328(struct rk_tsadc_softc *, int, int); | 219 | static void rk_tsadc_init_rk3328(struct rk_tsadc_softc *, int, int); | |
220 | static void rk_tsadc_init_rk3399(struct rk_tsadc_softc *, int, int); | 220 | static void rk_tsadc_init_rk3399(struct rk_tsadc_softc *, int, int); | |
221 | static void rk_tsadc_init_enable(struct rk_tsadc_softc *); | 221 | static void rk_tsadc_init_enable(struct rk_tsadc_softc *); | |
222 | static void rk_tsadc_init(struct rk_tsadc_softc *, int, int); | 222 | static void rk_tsadc_init(struct rk_tsadc_softc *, int, int); | |
223 | static void rk_tsadc_refresh(struct sysmon_envsys *, envsys_data_t *); | 223 | static void rk_tsadc_refresh(struct sysmon_envsys *, envsys_data_t *); | |
224 | static void rk_tsadc_get_limits(struct sysmon_envsys *, envsys_data_t *, | 224 | static void rk_tsadc_get_limits(struct sysmon_envsys *, envsys_data_t *, | |
225 | sysmon_envsys_lim_t *, uint32_t *); | 225 | sysmon_envsys_lim_t *, uint32_t *); | |
226 | 226 | |||
227 | static int rk_tsadc_intr(void *); | 227 | static int rk_tsadc_intr(void *); | |
228 | static int rk_tsadc_data_to_temp(struct rk_tsadc_softc *, uint32_t); | 228 | static int rk_tsadc_data_to_temp(struct rk_tsadc_softc *, uint32_t); | |
229 | static uint32_t rk_tsadc_temp_to_data(struct rk_tsadc_softc *, int); | 229 | static uint32_t rk_tsadc_temp_to_data(struct rk_tsadc_softc *, int); | |
230 | 230 | |||
231 | /* RK3328/RK3399 compatible sensors */ | 231 | /* RK3328/RK3399 compatible sensors */ | |
232 | static const struct rk_tsadc_sensor rk_tsadc_sensors[] = { | 232 | static const struct rk_tsadc_sensor rk_tsadc_sensors[] = { | |
233 | { | 233 | { | |
234 | .s_data = { .desc = "CPU" }, | 234 | .s_data = { .desc = "CPU" }, | |
235 | .s_data_reg = TSADC_DATA0, | 235 | .s_data_reg = TSADC_DATA0, | |
236 | .s_comp_tshut = TSADC_COMP0_SHUT, | 236 | .s_comp_tshut = TSADC_COMP0_SHUT, | |
237 | .s_comp_int = TSADC_COMP0_INT, | 237 | .s_comp_int = TSADC_COMP0_INT, | |
238 | .s_comp_int_en = TSADC_AUTO_CON_SRC0_EN, | 238 | .s_comp_int_en = TSADC_AUTO_CON_SRC0_EN, | |
239 | /* | 239 | /* | |
240 | * XXX DT has: | 240 | * XXX DT has: | |
241 | * cpu_alert1: cpu_alert1 { | 241 | * cpu_alert1: cpu_alert1 { | |
242 | * temperature = <75000>; | 242 | * temperature = <75000>; | |
243 | * hysteresis = <2000>; | 243 | * hysteresis = <2000>; | |
244 | * cpu_crit: cpu_crit { | 244 | * cpu_crit: cpu_crit { | |
245 | * temperature = <95000>; | 245 | * temperature = <95000>; | |
246 | * hysteresis = <2000>; | 246 | * hysteresis = <2000>; | |
247 | * pull out of here? | 247 | * pull out of here? | |
248 | * do something with hysteresis? put in debounce? | 248 | * do something with hysteresis? put in debounce? | |
249 | * | 249 | * | |
250 | * Note that tshut may be overriden by the board specific DT. | 250 | * Note that tshut may be overriden by the board specific DT. | |
251 | */ | 251 | */ | |
252 | .s_warn = 75000000, | 252 | .s_warn = 75000000, | |
253 | .s_tshut = 95000000, | 253 | .s_tshut = 95000000, | |
254 | }, { | 254 | }, { | |
255 | .s_data = { .desc = "GPU" }, | 255 | .s_data = { .desc = "GPU" }, | |
256 | .s_data_reg = TSADC_DATA1, | 256 | .s_data_reg = TSADC_DATA1, | |
257 | .s_comp_tshut = TSADC_COMP1_SHUT, | 257 | .s_comp_tshut = TSADC_COMP1_SHUT, | |
258 | .s_comp_int = TSADC_COMP1_INT, | 258 | .s_comp_int = TSADC_COMP1_INT, | |
259 | .s_comp_int_en = TSADC_AUTO_CON_SRC1_EN, | 259 | .s_comp_int_en = TSADC_AUTO_CON_SRC1_EN, | |
260 | .s_warn = 75000000, | 260 | .s_warn = 75000000, | |
261 | .s_tshut = 95000000, | 261 | .s_tshut = 95000000, | |
262 | }, | 262 | }, | |
263 | }; | 263 | }; | |
264 | 264 | |||
265 | /* | 265 | /* | |
266 | * Table from RK3328 manual. Note that the manual lists valid numbers as | 266 | * Table from RK3328 manual. Note that the manual lists valid numbers as | |
267 | * 4096 - number. This also means it is increasing not decreasing for | 267 | * 4096 - number. This also means it is increasing not decreasing for | |
268 | * higher temps, and the min and max are also offset from 4096. | 268 | * higher temps, and the min and max are also offset from 4096. | |
269 | */ | 269 | */ | |
270 | #define RK3328_DATA_OFFSET (4096) | 270 | #define RK3328_DATA_OFFSET (4096) | |
271 | static const rk_data_array rk3328_data_array[] = { | 271 | static const rk_data_array rk3328_data_array[] = { | |
272 | #define ENTRY(d,C) \ | 272 | #define ENTRY(d,C) \ | |
273 | { .data = RK3328_DATA_OFFSET - (d), .temp = (C) * 1000 * 1000, } | 273 | { .data = RK3328_DATA_OFFSET - (d), .temp = (C) * 1000 * 1000, } | |
274 | ENTRY(TSADC_DATA_MAX, -40), | 274 | ENTRY(TSADC_DATA_MAX, -40), | |
275 | ENTRY(3800, -40), | 275 | ENTRY(3800, -40), | |
276 | ENTRY(3792, -35), | 276 | ENTRY(3792, -35), | |
277 | ENTRY(3783, -30), | 277 | ENTRY(3783, -30), | |
278 | ENTRY(3774, -25), | 278 | ENTRY(3774, -25), | |
279 | ENTRY(3765, -20), | 279 | ENTRY(3765, -20), | |
280 | ENTRY(3756, -15), | 280 | ENTRY(3756, -15), | |
281 | ENTRY(3747, -10), | 281 | ENTRY(3747, -10), | |
282 | ENTRY(3737, -5), | 282 | ENTRY(3737, -5), | |
283 | ENTRY(3728, 0), | 283 | ENTRY(3728, 0), | |
284 | ENTRY(3718, 5), | 284 | ENTRY(3718, 5), | |
285 | ENTRY(3708, 10), | 285 | ENTRY(3708, 10), | |
286 | ENTRY(3698, 15), | 286 | ENTRY(3698, 15), | |
287 | ENTRY(3688, 20), | 287 | ENTRY(3688, 20), | |
288 | ENTRY(3678, 25), | 288 | ENTRY(3678, 25), | |
289 | ENTRY(3667, 30), | 289 | ENTRY(3667, 30), | |
290 | ENTRY(3656, 35), | 290 | ENTRY(3656, 35), | |
291 | ENTRY(3645, 40), | 291 | ENTRY(3645, 40), | |
292 | ENTRY(3634, 45), | 292 | ENTRY(3634, 45), | |
293 | ENTRY(3623, 50), | 293 | ENTRY(3623, 50), | |
294 | ENTRY(3611, 55), | 294 | ENTRY(3611, 55), | |
295 | ENTRY(3600, 60), | 295 | ENTRY(3600, 60), | |
296 | ENTRY(3588, 65), | 296 | ENTRY(3588, 65), | |
297 | ENTRY(3575, 70), | 297 | ENTRY(3575, 70), | |
298 | ENTRY(3563, 75), | 298 | ENTRY(3563, 75), | |
299 | ENTRY(3550, 80), | 299 | ENTRY(3550, 80), | |
300 | ENTRY(3537, 85), | 300 | ENTRY(3537, 85), | |
301 | ENTRY(3524, 90), | 301 | ENTRY(3524, 90), | |
302 | ENTRY(3510, 95), | 302 | ENTRY(3510, 95), | |
303 | ENTRY(3496, 100), | 303 | ENTRY(3496, 100), | |
304 | ENTRY(3482, 105), | 304 | ENTRY(3482, 105), | |
305 | ENTRY(3467, 110), | 305 | ENTRY(3467, 110), | |
306 | ENTRY(3452, 115), | 306 | ENTRY(3452, 115), | |
307 | ENTRY(3437, 120), | 307 | ENTRY(3437, 120), | |
308 | ENTRY(3421, 125), | 308 | ENTRY(3421, 125), | |
309 | ENTRY(0, 125), | 309 | ENTRY(0, 125), | |
310 | #undef ENTRY | 310 | #undef ENTRY | |
311 | }; | 311 | }; | |
312 | 312 | |||
313 | /* Table from RK3399 manual */ | 313 | /* Table from RK3399 manual */ | |
314 | static const rk_data_array rk3399_data_array[] = { | 314 | static const rk_data_array rk3399_data_array[] = { | |
315 | #define ENTRY(d,C) { .data = (d), .temp = (C) * 1000 * 1000, } | 315 | #define ENTRY(d,C) { .data = (d), .temp = (C) * 1000 * 1000, } | |
316 | ENTRY(0, -40), | 316 | ENTRY(0, -40), | |
317 | ENTRY(402, -40), | 317 | ENTRY(402, -40), | |
318 | ENTRY(410, -35), | 318 | ENTRY(410, -35), | |
319 | ENTRY(419, -30), | 319 | ENTRY(419, -30), | |
320 | ENTRY(427, -25), | 320 | ENTRY(427, -25), | |
321 | ENTRY(436, -20), | 321 | ENTRY(436, -20), | |
322 | ENTRY(444, -15), | 322 | ENTRY(444, -15), | |
323 | ENTRY(453, -10), | 323 | ENTRY(453, -10), | |
324 | ENTRY(461, -5), | 324 | ENTRY(461, -5), | |
325 | ENTRY(470, 0), | 325 | ENTRY(470, 0), | |
326 | ENTRY(478, 5), | 326 | ENTRY(478, 5), | |
327 | ENTRY(487, 10), | 327 | ENTRY(487, 10), | |
328 | ENTRY(496, 15), | 328 | ENTRY(496, 15), | |
329 | ENTRY(504, 20), | 329 | ENTRY(504, 20), | |
330 | ENTRY(513, 25), | 330 | ENTRY(513, 25), | |
331 | ENTRY(521, 30), | 331 | ENTRY(521, 30), | |
332 | ENTRY(530, 35), | 332 | ENTRY(530, 35), | |
333 | ENTRY(538, 40), | 333 | ENTRY(538, 40), | |
334 | ENTRY(547, 45), | 334 | ENTRY(547, 45), | |
335 | ENTRY(555, 50), | 335 | ENTRY(555, 50), | |
336 | ENTRY(564, 55), | 336 | ENTRY(564, 55), | |
337 | ENTRY(573, 60), | 337 | ENTRY(573, 60), | |
338 | ENTRY(581, 65), | 338 | ENTRY(581, 65), | |
339 | ENTRY(590, 70), | 339 | ENTRY(590, 70), | |
340 | ENTRY(599, 75), | 340 | ENTRY(599, 75), | |
341 | ENTRY(607, 80), | 341 | ENTRY(607, 80), | |
342 | ENTRY(616, 85), | 342 | ENTRY(616, 85), | |
343 | ENTRY(624, 90), | 343 | ENTRY(624, 90), | |
344 | ENTRY(633, 95), | 344 | ENTRY(633, 95), | |
345 | ENTRY(642, 100), | 345 | ENTRY(642, 100), | |
346 | ENTRY(650, 105), | 346 | ENTRY(650, 105), | |
347 | ENTRY(659, 110), | 347 | ENTRY(659, 110), | |
348 | ENTRY(668, 115), | 348 | ENTRY(668, 115), | |
349 | ENTRY(677, 120), | 349 | ENTRY(677, 120), | |
350 | ENTRY(685, 125), | 350 | ENTRY(685, 125), | |
351 | ENTRY(TSADC_DATA_MAX, 125), | 351 | ENTRY(TSADC_DATA_MAX, 125), | |
352 | #undef ENTRY | 352 | #undef ENTRY | |
353 | }; | 353 | }; | |
354 | 354 | |||
355 | static const rk_data rk3328_data_table = { | 355 | static const rk_data rk3328_data_table = { | |
356 | .rd_array = rk3328_data_array, | 356 | .rd_array = rk3328_data_array, | |
357 | .rd_size = __arraycount(rk3328_data_array), | 357 | .rd_size = __arraycount(rk3328_data_array), | |
358 | .rd_init = rk_tsadc_init_rk3328, | 358 | .rd_init = rk_tsadc_init_rk3328, | |
359 | .rd_decr = false, | 359 | .rd_decr = false, | |
360 | .rd_max = RK3328_DATA_OFFSET - 3420, | 360 | .rd_max = RK3328_DATA_OFFSET - 3420, | |
361 | .rd_min = RK3328_DATA_OFFSET - 3801, | 361 | .rd_min = RK3328_DATA_OFFSET - 3801, | |
362 | .rd_auto_period = RK3328_TSADC_AUTO_PERIOD_TIME, | 362 | .rd_auto_period = RK3328_TSADC_AUTO_PERIOD_TIME, | |
363 | .rd_num_sensors = 1, | 363 | .rd_num_sensors = 1, | |
364 | }; | 364 | }; | |
365 | 365 | |||
366 | static const rk_data rk3399_data_table = { | 366 | static const rk_data rk3399_data_table = { | |
367 | .rd_array = rk3399_data_array, | 367 | .rd_array = rk3399_data_array, | |
368 | .rd_size = __arraycount(rk3399_data_array), | 368 | .rd_size = __arraycount(rk3399_data_array), | |
369 | .rd_init = rk_tsadc_init_rk3399, | 369 | .rd_init = rk_tsadc_init_rk3399, | |
370 | .rd_decr = false, | 370 | .rd_decr = false, | |
371 | .rd_max = 686, | 371 | .rd_max = 686, | |
372 | .rd_min = 401, | 372 | .rd_min = 401, | |
373 | .rd_auto_period = RK3399_TSADC_AUTO_PERIOD_TIME, | 373 | .rd_auto_period = RK3399_TSADC_AUTO_PERIOD_TIME, | |
374 | .rd_num_sensors = 2, | 374 | .rd_num_sensors = 2, | |
375 | }; | 375 | }; | |
376 | 376 | |||
377 | static const struct device_compatible_entry compat_data[] = { | 377 | static const struct device_compatible_entry compat_data[] = { | |
378 | { .compat = "rockchip,rk3328-tsadc", .data = &rk3328_data_table }, | 378 | { .compat = "rockchip,rk3328-tsadc", .data = &rk3328_data_table }, | |
379 | { .compat = "rockchip,rk3399-tsadc", .data = &rk3399_data_table }, | 379 | { .compat = "rockchip,rk3399-tsadc", .data = &rk3399_data_table }, | |
380 | { } | 380 | DEVICE_COMPAT_EOL | |
381 | }; | 381 | }; | |
382 | 382 | |||
383 | #define TSADC_READ(sc, reg) \ | 383 | #define TSADC_READ(sc, reg) \ | |
384 | bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) | 384 | bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) | |
385 | #define TSADC_WRITE(sc, reg, val) \ | 385 | #define TSADC_WRITE(sc, reg, val) \ | |
386 | bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) | 386 | bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) | |
387 | 387 | |||
388 | CFATTACH_DECL3_NEW(rk_tsadc, sizeof(struct rk_tsadc_softc), | 388 | CFATTACH_DECL3_NEW(rk_tsadc, sizeof(struct rk_tsadc_softc), | |
389 | rk_tsadc_match, rk_tsadc_attach, rk_tsadc_detach, NULL, NULL, NULL, | 389 | rk_tsadc_match, rk_tsadc_attach, rk_tsadc_detach, NULL, NULL, NULL, | |
390 | DVF_DETACH_SHUTDOWN); | 390 | DVF_DETACH_SHUTDOWN); | |
391 | 391 | |||
392 | /* init/teardown support */ | 392 | /* init/teardown support */ | |
393 | static int | 393 | static int | |
394 | rk_tsadc_match(device_t parent, cfdata_t cf, void *aux) | 394 | rk_tsadc_match(device_t parent, cfdata_t cf, void *aux) | |
395 | { | 395 | { | |
396 | struct fdt_attach_args * const faa = aux; | 396 | struct fdt_attach_args * const faa = aux; | |
397 | 397 | |||
398 | return of_match_compat_data(faa->faa_phandle, compat_data); | 398 | return of_match_compat_data(faa->faa_phandle, compat_data); | |
399 | } | 399 | } | |
400 | 400 | |||
401 | static void | 401 | static void | |
402 | rk_tsadc_attach(device_t parent, device_t self, void *aux) | 402 | rk_tsadc_attach(device_t parent, device_t self, void *aux) | |
403 | { | 403 | { | |
404 | struct rk_tsadc_softc * const sc = device_private(self); | 404 | struct rk_tsadc_softc * const sc = device_private(self); | |
405 | struct fdt_attach_args * const faa = aux; | 405 | struct fdt_attach_args * const faa = aux; | |
406 | char intrstr[128]; | 406 | char intrstr[128]; | |
407 | const int phandle = faa->faa_phandle; | 407 | const int phandle = faa->faa_phandle; | |
408 | bus_addr_t addr; | 408 | bus_addr_t addr; | |
409 | int mode, polarity, tshut_temp; | 409 | int mode, polarity, tshut_temp; | |
410 | 410 | |||
411 | sc->sc_dev = self; | 411 | sc->sc_dev = self; | |
412 | sc->sc_phandle = phandle; | 412 | sc->sc_phandle = phandle; | |
413 | sc->sc_bst = faa->faa_bst; | 413 | sc->sc_bst = faa->faa_bst; | |
414 | 414 | |||
415 | aprint_naive("\n"); | 415 | aprint_naive("\n"); | |
416 | aprint_normal(": RK3328/3399 Temperature Sensor ADC\n"); | 416 | aprint_normal(": RK3328/3399 Temperature Sensor ADC\n"); | |
417 | 417 | |||
418 | sc->sc_sme = sysmon_envsys_create(); | 418 | sc->sc_sme = sysmon_envsys_create(); | |
419 | 419 | |||
420 | sc->sc_sme->sme_name = device_xname(self); | 420 | sc->sc_sme->sme_name = device_xname(self); | |
421 | sc->sc_sme->sme_cookie = sc; | 421 | sc->sc_sme->sme_cookie = sc; | |
422 | sc->sc_sme->sme_refresh = rk_tsadc_refresh; | 422 | sc->sc_sme->sme_refresh = rk_tsadc_refresh; | |
423 | sc->sc_sme->sme_get_limits = rk_tsadc_get_limits; | 423 | sc->sc_sme->sme_get_limits = rk_tsadc_get_limits; | |
424 | sc->sc_data_mask = TSADC_DATA_MAX; | 424 | sc->sc_data_mask = TSADC_DATA_MAX; | |
425 | 425 | |||
426 | pmf_device_register(self, NULL, NULL); | 426 | pmf_device_register(self, NULL, NULL); | |
427 | 427 | |||
428 | sc->sc_rd = of_search_compatible(faa->faa_phandle, compat_data)->data; | 428 | sc->sc_rd = of_search_compatible(faa->faa_phandle, compat_data)->data; | |
429 | 429 | |||
430 | /* Default to tshut via gpio and tshut low is active */ | 430 | /* Default to tshut via gpio and tshut low is active */ | |
431 | if (of_getprop_uint32(phandle, "rockchip,hw-tshut-mode", | 431 | if (of_getprop_uint32(phandle, "rockchip,hw-tshut-mode", | |
432 | &mode) != 0) { | 432 | &mode) != 0) { | |
433 | aprint_error(": could not get TSHUT mode, default to GPIO"); | 433 | aprint_error(": could not get TSHUT mode, default to GPIO"); | |
434 | mode = TSHUT_MODE_GPIO; | 434 | mode = TSHUT_MODE_GPIO; | |
435 | } | 435 | } | |
436 | if (mode != TSHUT_MODE_CPU && mode != TSHUT_MODE_GPIO) { | 436 | if (mode != TSHUT_MODE_CPU && mode != TSHUT_MODE_GPIO) { | |
437 | aprint_error(": TSHUT mode should be 0 or 1\n"); | 437 | aprint_error(": TSHUT mode should be 0 or 1\n"); | |
438 | goto fail; | 438 | goto fail; | |
439 | } | 439 | } | |
440 | 440 | |||
441 | if (of_getprop_uint32(phandle, "rockchip,hw-tshut-polarity", | 441 | if (of_getprop_uint32(phandle, "rockchip,hw-tshut-polarity", | |
442 | &polarity) != 0) { | 442 | &polarity) != 0) { | |
443 | aprint_error(": could not get TSHUT polarity, default to low"); | 443 | aprint_error(": could not get TSHUT polarity, default to low"); | |
444 | polarity = TSHUT_LOW_ACTIVE; | 444 | polarity = TSHUT_LOW_ACTIVE; | |
445 | } | 445 | } | |
446 | if (of_getprop_uint32(phandle, | 446 | if (of_getprop_uint32(phandle, | |
447 | "rockchip,hw-tshut-temp", &tshut_temp) != 0) { | 447 | "rockchip,hw-tshut-temp", &tshut_temp) != 0) { | |
448 | aprint_error(": could not get TSHUT temperature, default to %u", | 448 | aprint_error(": could not get TSHUT temperature, default to %u", | |
449 | TSHUT_DEF_TEMP); | 449 | TSHUT_DEF_TEMP); | |
450 | tshut_temp = TSHUT_DEF_TEMP; | 450 | tshut_temp = TSHUT_DEF_TEMP; | |
451 | } | 451 | } | |
452 | tshut_temp *= 1000; /* convert fdt ms -> us */ | 452 | tshut_temp *= 1000; /* convert fdt ms -> us */ | |
453 | 453 | |||
454 | memcpy(sc->sc_sensors, rk_tsadc_sensors, sizeof(sc->sc_sensors)); | 454 | memcpy(sc->sc_sensors, rk_tsadc_sensors, sizeof(sc->sc_sensors)); | |
455 | for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) { | 455 | for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) { | |
456 | struct rk_tsadc_sensor *rks = &sc->sc_sensors[n]; | 456 | struct rk_tsadc_sensor *rks = &sc->sc_sensors[n]; | |
457 | 457 | |||
458 | rks->s_data.flags = ENVSYS_FMONLIMITS; | 458 | rks->s_data.flags = ENVSYS_FMONLIMITS; | |
459 | rks->s_data.units = ENVSYS_STEMP; | 459 | rks->s_data.units = ENVSYS_STEMP; | |
460 | rks->s_data.state = ENVSYS_SINVALID; | 460 | rks->s_data.state = ENVSYS_SINVALID; | |
461 | 461 | |||
462 | if (sysmon_envsys_sensor_attach(sc->sc_sme, &rks->s_data)) | 462 | if (sysmon_envsys_sensor_attach(sc->sc_sme, &rks->s_data)) | |
463 | goto fail; | 463 | goto fail; | |
464 | rks->s_attached = true; | 464 | rks->s_attached = true; | |
465 | rks->s_tshut = tshut_temp; | 465 | rks->s_tshut = tshut_temp; | |
466 | #if 0 | 466 | #if 0 | |
467 | // testing | 467 | // testing | |
468 | rks->s_tshut = 68000000; | 468 | rks->s_tshut = 68000000; | |
469 | rks->s_warn = 61000000; | 469 | rks->s_warn = 61000000; | |
470 | #endif | 470 | #endif | |
471 | } | 471 | } | |
472 | 472 | |||
473 | sc->sc_syscon = fdtbus_syscon_acquire(phandle, "rockchip,grf"); | 473 | sc->sc_syscon = fdtbus_syscon_acquire(phandle, "rockchip,grf"); | |
474 | if (sc->sc_syscon == NULL) { | 474 | if (sc->sc_syscon == NULL) { | |
475 | aprint_error(": couldn't get grf syscon\n"); | 475 | aprint_error(": couldn't get grf syscon\n"); | |
476 | goto fail; | 476 | goto fail; | |
477 | } | 477 | } | |
478 | if (fdtbus_get_reg(phandle, 0, &addr, &sc->sc_size) != 0) { | 478 | if (fdtbus_get_reg(phandle, 0, &addr, &sc->sc_size) != 0) { | |
479 | aprint_error(": couldn't get registers\n"); | 479 | aprint_error(": couldn't get registers\n"); | |
480 | sc->sc_size = 0; | 480 | sc->sc_size = 0; | |
481 | goto fail; | 481 | goto fail; | |
482 | } | 482 | } | |
483 | if (bus_space_map(sc->sc_bst, addr, sc->sc_size, 0, &sc->sc_bsh) != 0) { | 483 | if (bus_space_map(sc->sc_bst, addr, sc->sc_size, 0, &sc->sc_bsh) != 0) { | |
484 | aprint_error(": couldn't map registers\n"); | 484 | aprint_error(": couldn't map registers\n"); | |
485 | sc->sc_size = 0; | 485 | sc->sc_size = 0; | |
486 | goto fail; | 486 | goto fail; | |
487 | } | 487 | } | |
488 | 488 | |||
489 | if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { | 489 | if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { | |
490 | aprint_error(": failed to decode interrupt\n"); | 490 | aprint_error(": failed to decode interrupt\n"); | |
491 | goto fail; | 491 | goto fail; | |
492 | } | 492 | } | |
493 | 493 | |||
494 | sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, FDT_INTR_MPSAFE, | 494 | sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, FDT_INTR_MPSAFE, | |
495 | rk_tsadc_intr, sc, device_xname(self)); | 495 | rk_tsadc_intr, sc, device_xname(self)); | |
496 | if (sc->sc_ih == NULL) { | 496 | if (sc->sc_ih == NULL) { | |
497 | aprint_error_dev(self, "couldn't establish interrupt on %s\n", | 497 | aprint_error_dev(self, "couldn't establish interrupt on %s\n", | |
498 | intrstr); | 498 | intrstr); | |
499 | goto fail; | 499 | goto fail; | |
500 | } | 500 | } | |
501 | aprint_normal_dev(self, "interrupting on %s\n", intrstr); | 501 | aprint_normal_dev(self, "interrupting on %s\n", intrstr); | |
502 | 502 | |||
503 | if (rk_tsadc_init_clocks(sc)) { | 503 | if (rk_tsadc_init_clocks(sc)) { | |
504 | aprint_error(": couldn't enable clocks\n"); | 504 | aprint_error(": couldn't enable clocks\n"); | |
505 | return; | 505 | return; | |
506 | } | 506 | } | |
507 | 507 | |||
508 | /* | 508 | /* | |
509 | * Manual says to setup auto period (both), high temp (interrupt), | 509 | * Manual says to setup auto period (both), high temp (interrupt), | |
510 | * high temp (shutdown), enable high temp resets (TSHUT to GPIO | 510 | * high temp (shutdown), enable high temp resets (TSHUT to GPIO | |
511 | * or reset chip), set the debounce times, and, finally, enable the | 511 | * or reset chip), set the debounce times, and, finally, enable the | |
512 | * controller iself. | 512 | * controller iself. | |
513 | */ | 513 | */ | |
514 | rk_tsadc_init(sc, mode, polarity); | 514 | rk_tsadc_init(sc, mode, polarity); | |
515 | 515 | |||
516 | return; | 516 | return; | |
517 | 517 | |||
518 | fail: | 518 | fail: | |
519 | rk_tsadc_detach(self, 0); | 519 | rk_tsadc_detach(self, 0); | |
520 | } | 520 | } | |
521 | 521 | |||
522 | static int | 522 | static int | |
523 | rk_tsadc_detach(device_t self, int flags) | 523 | rk_tsadc_detach(device_t self, int flags) | |
524 | { | 524 | { | |
525 | struct rk_tsadc_softc *sc = device_private(self); | 525 | struct rk_tsadc_softc *sc = device_private(self); | |
526 | 526 | |||
527 | pmf_device_deregister(self); | 527 | pmf_device_deregister(self); | |
528 | 528 | |||
529 | for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) { | 529 | for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) { | |
530 | struct rk_tsadc_sensor *rks = &sc->sc_sensors[n]; | 530 | struct rk_tsadc_sensor *rks = &sc->sc_sensors[n]; | |
531 | 531 | |||
532 | if (rks->s_attached) { | 532 | if (rks->s_attached) { | |
533 | sysmon_envsys_sensor_detach(sc->sc_sme, &rks->s_data); | 533 | sysmon_envsys_sensor_detach(sc->sc_sme, &rks->s_data); | |
534 | rks->s_attached = false; | 534 | rks->s_attached = false; | |
535 | } | 535 | } | |
536 | } | 536 | } | |
537 | 537 | |||
538 | sysmon_envsys_unregister(sc->sc_sme); | 538 | sysmon_envsys_unregister(sc->sc_sme); | |
539 | 539 | |||
540 | if (sc->sc_clockapb) | 540 | if (sc->sc_clockapb) | |
541 | clk_disable(sc->sc_clockapb); | 541 | clk_disable(sc->sc_clockapb); | |
542 | if (sc->sc_clock) | 542 | if (sc->sc_clock) | |
543 | clk_disable(sc->sc_clock); | 543 | clk_disable(sc->sc_clock); | |
544 | 544 | |||
545 | if (sc->sc_ih) | 545 | if (sc->sc_ih) | |
546 | fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih); | 546 | fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih); | |
547 | 547 | |||
548 | if (sc->sc_size) | 548 | if (sc->sc_size) | |
549 | bus_space_unmap(sc->sc_bst, sc->sc_bsh, sc->sc_size); | 549 | bus_space_unmap(sc->sc_bst, sc->sc_bsh, sc->sc_size); | |
550 | 550 | |||
551 | sysmon_envsys_destroy(sc->sc_sme); | 551 | sysmon_envsys_destroy(sc->sc_sme); | |
552 | 552 | |||
553 | return 0; | 553 | return 0; | |
554 | } | 554 | } | |
555 | 555 | |||
556 | static int | 556 | static int | |
557 | rk_tsadc_init_clocks(struct rk_tsadc_softc *sc) | 557 | rk_tsadc_init_clocks(struct rk_tsadc_softc *sc) | |
558 | { | 558 | { | |
559 | int error; | 559 | int error; | |
560 | 560 | |||
561 | fdtbus_clock_assign(sc->sc_phandle); | 561 | fdtbus_clock_assign(sc->sc_phandle); | |
562 | 562 | |||
563 | sc->sc_reset = fdtbus_reset_get(sc->sc_phandle, "tsadc-apb"); | 563 | sc->sc_reset = fdtbus_reset_get(sc->sc_phandle, "tsadc-apb"); | |
564 | sc->sc_clock = fdtbus_clock_get(sc->sc_phandle, "tsadc"); | 564 | sc->sc_clock = fdtbus_clock_get(sc->sc_phandle, "tsadc"); | |
565 | sc->sc_clockapb = fdtbus_clock_get(sc->sc_phandle, "apb_pclk"); | 565 | sc->sc_clockapb = fdtbus_clock_get(sc->sc_phandle, "apb_pclk"); | |
566 | if (sc->sc_reset == NULL || | 566 | if (sc->sc_reset == NULL || | |
567 | sc->sc_clock == NULL || | 567 | sc->sc_clock == NULL || | |
568 | sc->sc_clockapb == NULL) | 568 | sc->sc_clockapb == NULL) | |
569 | return EINVAL; | 569 | return EINVAL; | |
570 | 570 | |||
571 | fdtbus_reset_assert(sc->sc_reset); | 571 | fdtbus_reset_assert(sc->sc_reset); | |
572 | 572 | |||
573 | error = clk_enable(sc->sc_clock); | 573 | error = clk_enable(sc->sc_clock); | |
574 | if (error) { | 574 | if (error) { | |
575 | fdtbus_reset_deassert(sc->sc_reset); | 575 | fdtbus_reset_deassert(sc->sc_reset); | |
576 | return error; | 576 | return error; | |
577 | } | 577 | } | |
578 | 578 | |||
579 | error = clk_enable(sc->sc_clockapb); | 579 | error = clk_enable(sc->sc_clockapb); | |
580 | 580 | |||
581 | DELAY(20); | 581 | DELAY(20); | |
582 | fdtbus_reset_deassert(sc->sc_reset); | 582 | fdtbus_reset_deassert(sc->sc_reset); | |
583 | 583 | |||
584 | return error; | 584 | return error; | |
585 | } | 585 | } | |
586 | 586 | |||
587 | static void | 587 | static void | |
588 | rk_tsadc_init_counts(struct rk_tsadc_softc *sc) | 588 | rk_tsadc_init_counts(struct rk_tsadc_softc *sc) | |
589 | { | 589 | { | |
590 | 590 | |||
591 | TSADC_WRITE(sc, TSADC_AUTO_PERIOD, sc->sc_rd->rd_auto_period); | 591 | TSADC_WRITE(sc, TSADC_AUTO_PERIOD, sc->sc_rd->rd_auto_period); | |
592 | TSADC_WRITE(sc, TSADC_AUTO_PERIOD_HT, sc->sc_rd->rd_auto_period); | 592 | TSADC_WRITE(sc, TSADC_AUTO_PERIOD_HT, sc->sc_rd->rd_auto_period); | |
593 | TSADC_WRITE(sc, TSADC_HIGH_INT_DEBOUNCE, TSADC_HT_DEBOUNCE_COUNT); | 593 | TSADC_WRITE(sc, TSADC_HIGH_INT_DEBOUNCE, TSADC_HT_DEBOUNCE_COUNT); | |
594 | TSADC_WRITE(sc, TSADC_HIGH_TSHUT_DEBOUNCE, TSADC_HT_DEBOUNCE_COUNT); | 594 | TSADC_WRITE(sc, TSADC_HIGH_TSHUT_DEBOUNCE, TSADC_HT_DEBOUNCE_COUNT); | |
595 | } | 595 | } | |
596 | 596 | |||
597 | /* Configure the hardware with the tshut setup. */ | 597 | /* Configure the hardware with the tshut setup. */ | |
598 | static void | 598 | static void | |
599 | rk_tsadc_tshut_set(struct rk_tsadc_softc *sc) | 599 | rk_tsadc_tshut_set(struct rk_tsadc_softc *sc) | |
600 | { | 600 | { | |
601 | uint32_t val = TSADC_READ(sc, TSADC_AUTO_CON); | 601 | uint32_t val = TSADC_READ(sc, TSADC_AUTO_CON); | |
602 | 602 | |||
603 | for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) { | 603 | for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) { | |
604 | struct rk_tsadc_sensor *rks = &sc->sc_sensors[n]; | 604 | struct rk_tsadc_sensor *rks = &sc->sc_sensors[n]; | |
605 | uint32_t data, warndata; | 605 | uint32_t data, warndata; | |
606 | 606 | |||
607 | if (!rks->s_attached) | 607 | if (!rks->s_attached) | |
608 | continue; | 608 | continue; | |
609 | 609 | |||
610 | data = rk_tsadc_temp_to_data(sc, rks->s_tshut); | 610 | data = rk_tsadc_temp_to_data(sc, rks->s_tshut); | |
611 | warndata = rk_tsadc_temp_to_data(sc, rks->s_warn); | 611 | warndata = rk_tsadc_temp_to_data(sc, rks->s_warn); | |
612 | 612 | |||
613 | DPRINTF("(%s:%s): tshut/data %d/%u warn/data %d/%u", | 613 | DPRINTF("(%s:%s): tshut/data %d/%u warn/data %d/%u", | |
614 | sc->sc_sme->sme_name, rks->s_data.desc, | 614 | sc->sc_sme->sme_name, rks->s_data.desc, | |
615 | rks->s_tshut, data, | 615 | rks->s_tshut, data, | |
616 | rks->s_warn, warndata); | 616 | rks->s_warn, warndata); | |
617 | 617 | |||
618 | if (data == sc->sc_data_mask) { | 618 | if (data == sc->sc_data_mask) { | |
619 | aprint_error_dev(sc->sc_dev, | 619 | aprint_error_dev(sc->sc_dev, | |
620 | "Failed converting critical temp %u.%06u to code", | 620 | "Failed converting critical temp %u.%06u to code", | |
621 | rks->s_tshut / 1000000, rks->s_tshut % 1000000); | 621 | rks->s_tshut / 1000000, rks->s_tshut % 1000000); | |
622 | continue; | 622 | continue; | |
623 | } | 623 | } | |
624 | if (warndata == sc->sc_data_mask) { | 624 | if (warndata == sc->sc_data_mask) { | |
625 | aprint_error_dev(sc->sc_dev, | 625 | aprint_error_dev(sc->sc_dev, | |
626 | "Failed converting warn temp %u.%06u to code", | 626 | "Failed converting warn temp %u.%06u to code", | |
627 | rks->s_warn / 1000000, rks->s_warn % 1000000); | 627 | rks->s_warn / 1000000, rks->s_warn % 1000000); | |
628 | continue; | 628 | continue; | |
629 | } | 629 | } | |
630 | 630 | |||
631 | TSADC_WRITE(sc, rks->s_comp_tshut, data); | 631 | TSADC_WRITE(sc, rks->s_comp_tshut, data); | |
632 | TSADC_WRITE(sc, rks->s_comp_int, warndata); | 632 | TSADC_WRITE(sc, rks->s_comp_int, warndata); | |
633 | 633 | |||
634 | val |= rks->s_comp_int_en; | 634 | val |= rks->s_comp_int_en; | |
635 | } | 635 | } | |
636 | TSADC_WRITE(sc, TSADC_AUTO_CON, val); | 636 | TSADC_WRITE(sc, TSADC_AUTO_CON, val); | |
637 | } | 637 | } | |
638 | 638 | |||
639 | static void | 639 | static void | |
640 | rk_tsadc_init_tshut(struct rk_tsadc_softc *sc, int mode, int polarity) | 640 | rk_tsadc_init_tshut(struct rk_tsadc_softc *sc, int mode, int polarity) | |
641 | { | 641 | { | |
642 | uint32_t val; | 642 | uint32_t val; | |
643 | 643 | |||
644 | /* Handle TSHUT temp setting. */ | 644 | /* Handle TSHUT temp setting. */ | |
645 | rk_tsadc_tshut_set(sc); | 645 | rk_tsadc_tshut_set(sc); | |
646 | 646 | |||
647 | /* Handle TSHUT mode setting. */ | 647 | /* Handle TSHUT mode setting. */ | |
648 | val = TSADC_READ(sc, TSADC_INT_EN); | 648 | val = TSADC_READ(sc, TSADC_INT_EN); | |
649 | if (mode == TSHUT_MODE_CPU) { | 649 | if (mode == TSHUT_MODE_CPU) { | |
650 | val |= TSADC_INT_EN_TSHUT_2CRU_EN_SRC1 | | 650 | val |= TSADC_INT_EN_TSHUT_2CRU_EN_SRC1 | | |
651 | TSADC_INT_EN_TSHUT_2CRU_EN_SRC0; | 651 | TSADC_INT_EN_TSHUT_2CRU_EN_SRC0; | |
652 | val &= ~(TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1 | | 652 | val &= ~(TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1 | | |
653 | TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0); | 653 | TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0); | |
654 | } else { | 654 | } else { | |
655 | KASSERT(mode == TSHUT_MODE_GPIO); | 655 | KASSERT(mode == TSHUT_MODE_GPIO); | |
656 | val &= ~(TSADC_INT_EN_TSHUT_2CRU_EN_SRC1 | | 656 | val &= ~(TSADC_INT_EN_TSHUT_2CRU_EN_SRC1 | | |
657 | TSADC_INT_EN_TSHUT_2CRU_EN_SRC0); | 657 | TSADC_INT_EN_TSHUT_2CRU_EN_SRC0); | |
658 | val |= TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1 | | 658 | val |= TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1 | | |
659 | TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0; | 659 | TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0; | |
660 | } | 660 | } | |
661 | TSADC_WRITE(sc, TSADC_INT_EN, val); | 661 | TSADC_WRITE(sc, TSADC_INT_EN, val); | |
662 | 662 | |||
663 | /* Handle TSHUT polarity setting. */ | 663 | /* Handle TSHUT polarity setting. */ | |
664 | val = TSADC_READ(sc, TSADC_AUTO_CON); | 664 | val = TSADC_READ(sc, TSADC_AUTO_CON); | |
665 | if (polarity == TSHUT_HIGH_ACTIVE) | 665 | if (polarity == TSHUT_HIGH_ACTIVE) | |
666 | val |= TSADC_AUTO_CON_TSHUT_POLARITY; | 666 | val |= TSADC_AUTO_CON_TSHUT_POLARITY; | |
667 | else | 667 | else | |
668 | val &= ~TSADC_AUTO_CON_TSHUT_POLARITY; | 668 | val &= ~TSADC_AUTO_CON_TSHUT_POLARITY; | |
669 | TSADC_WRITE(sc, TSADC_AUTO_CON, val); | 669 | TSADC_WRITE(sc, TSADC_AUTO_CON, val); | |
670 | } | 670 | } | |
671 | 671 | |||
672 | static void | 672 | static void | |
673 | rk_tsadc_init_rk3328(struct rk_tsadc_softc *sc, int mode, int polarity) | 673 | rk_tsadc_init_rk3328(struct rk_tsadc_softc *sc, int mode, int polarity) | |
674 | { | 674 | { | |
675 | 675 | |||
676 | rk_tsadc_init_tshut(sc, mode, polarity); | 676 | rk_tsadc_init_tshut(sc, mode, polarity); | |
677 | rk_tsadc_init_counts(sc); | 677 | rk_tsadc_init_counts(sc); | |
678 | } | 678 | } | |
679 | 679 | |||
680 | static void | 680 | static void | |
681 | rk_tsadc_init_rk3399(struct rk_tsadc_softc *sc, int mode, int polarity) | 681 | rk_tsadc_init_rk3399(struct rk_tsadc_softc *sc, int mode, int polarity) | |
682 | { | 682 | { | |
683 | 683 | |||
684 | syscon_lock(sc->sc_syscon); | 684 | syscon_lock(sc->sc_syscon); | |
685 | syscon_write_4(sc->sc_syscon, RK3399_GRF_TSADC_TESTBIT_L, | 685 | syscon_write_4(sc->sc_syscon, RK3399_GRF_TSADC_TESTBIT_L, | |
686 | RK3399_GRF_TSADC_TESTBIT_VCM_EN_L); | 686 | RK3399_GRF_TSADC_TESTBIT_VCM_EN_L); | |
687 | syscon_write_4(sc->sc_syscon, RK3399_GRF_TSADC_TESTBIT_H, | 687 | syscon_write_4(sc->sc_syscon, RK3399_GRF_TSADC_TESTBIT_H, | |
688 | RK3399_GRF_TSADC_TESTBIT_VCM_EN_H); | 688 | RK3399_GRF_TSADC_TESTBIT_VCM_EN_H); | |
689 | 689 | |||
690 | DELAY(20); | 690 | DELAY(20); | |
691 | syscon_write_4(sc->sc_syscon, RK3399_GRF_SARADC_TESTBIT, | 691 | syscon_write_4(sc->sc_syscon, RK3399_GRF_SARADC_TESTBIT, | |
692 | RK3399_GRF_SARADC_TESTBIT_ON); | 692 | RK3399_GRF_SARADC_TESTBIT_ON); | |
693 | syscon_write_4(sc->sc_syscon, RK3399_GRF_TSADC_TESTBIT_H, | 693 | syscon_write_4(sc->sc_syscon, RK3399_GRF_TSADC_TESTBIT_H, | |
694 | RK3399_GRF_TSADC_TESTBIT_H_ON); | 694 | RK3399_GRF_TSADC_TESTBIT_H_ON); | |
695 | DELAY(100); | 695 | DELAY(100); | |
696 | syscon_unlock(sc->sc_syscon); | 696 | syscon_unlock(sc->sc_syscon); | |
697 | 697 | |||
698 | rk_tsadc_init_counts(sc); | 698 | rk_tsadc_init_counts(sc); | |
699 | rk_tsadc_init_tshut(sc, mode, polarity); | 699 | rk_tsadc_init_tshut(sc, mode, polarity); | |
700 | } | 700 | } | |
701 | 701 | |||
702 | static void | 702 | static void | |
703 | rk_tsadc_init_enable(struct rk_tsadc_softc *sc) | 703 | rk_tsadc_init_enable(struct rk_tsadc_softc *sc) | |
704 | { | 704 | { | |
705 | uint32_t val; | 705 | uint32_t val; | |
706 | 706 | |||
707 | val = TSADC_READ(sc, TSADC_AUTO_CON); | 707 | val = TSADC_READ(sc, TSADC_AUTO_CON); | |
708 | val |= TSADC_AUTO_CON_AUTO_STATUS | | 708 | val |= TSADC_AUTO_CON_AUTO_STATUS | | |
709 | TSADC_AUTO_CON_SRC1_LT_EN | TSADC_AUTO_CON_SRC0_LT_EN; | 709 | TSADC_AUTO_CON_SRC1_LT_EN | TSADC_AUTO_CON_SRC0_LT_EN; | |
710 | TSADC_WRITE(sc, TSADC_AUTO_CON, val); | 710 | TSADC_WRITE(sc, TSADC_AUTO_CON, val); | |
711 | 711 | |||
712 | /* Finally, register & enable the controller */ | 712 | /* Finally, register & enable the controller */ | |
713 | sysmon_envsys_register(sc->sc_sme); | 713 | sysmon_envsys_register(sc->sc_sme); | |
714 | 714 | |||
715 | val = TSADC_READ(sc, TSADC_AUTO_CON); | 715 | val = TSADC_READ(sc, TSADC_AUTO_CON); | |
716 | val |= TSADC_AUTO_CON_AUTO_EN | TSADC_AUTO_CON_Q_SEL; | 716 | val |= TSADC_AUTO_CON_AUTO_EN | TSADC_AUTO_CON_Q_SEL; | |
717 | TSADC_WRITE(sc, TSADC_AUTO_CON, val); | 717 | TSADC_WRITE(sc, TSADC_AUTO_CON, val); | |
718 | } | 718 | } | |
719 | 719 | |||
720 | static void | 720 | static void | |
721 | rk_tsadc_init(struct rk_tsadc_softc *sc, int mode, int polarity) | 721 | rk_tsadc_init(struct rk_tsadc_softc *sc, int mode, int polarity) | |
722 | { | 722 | { | |
723 | 723 | |||
724 | (*sc->sc_rd->rd_init)(sc, mode, polarity); | 724 | (*sc->sc_rd->rd_init)(sc, mode, polarity); | |
725 | rk_tsadc_init_enable(sc); | 725 | rk_tsadc_init_enable(sc); | |
726 | } | 726 | } | |
727 | 727 | |||
728 | /* run time support */ | 728 | /* run time support */ | |
729 | 729 | |||
730 | /* given edata, find the matching rk sensor structure */ | 730 | /* given edata, find the matching rk sensor structure */ | |
731 | static struct rk_tsadc_sensor * | 731 | static struct rk_tsadc_sensor * | |
732 | rk_tsadc_edata_to_sensor(struct rk_tsadc_softc * const sc, envsys_data_t *edata) | 732 | rk_tsadc_edata_to_sensor(struct rk_tsadc_softc * const sc, envsys_data_t *edata) | |
733 | { | 733 | { | |
734 | 734 | |||
735 | for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) { | 735 | for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) { | |
736 | struct rk_tsadc_sensor *rks = &sc->sc_sensors[n]; | 736 | struct rk_tsadc_sensor *rks = &sc->sc_sensors[n]; | |
737 | 737 | |||
738 | if (&rks->s_data == edata) | 738 | if (&rks->s_data == edata) | |
739 | return rks; | 739 | return rks; | |
740 | } | 740 | } | |
741 | return NULL; | 741 | return NULL; | |
742 | } | 742 | } | |
743 | 743 | |||
744 | static void | 744 | static void | |
745 | rk_tsadc_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | 745 | rk_tsadc_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | |
746 | { | 746 | { | |
747 | struct rk_tsadc_softc * const sc = sme->sme_cookie; | 747 | struct rk_tsadc_softc * const sc = sme->sme_cookie; | |
748 | struct rk_tsadc_sensor *rks = rk_tsadc_edata_to_sensor(sc, edata); | 748 | struct rk_tsadc_sensor *rks = rk_tsadc_edata_to_sensor(sc, edata); | |
749 | unsigned data; | 749 | unsigned data; | |
750 | int temp; | 750 | int temp; | |
751 | 751 | |||
752 | if (rks == NULL) | 752 | if (rks == NULL) | |
753 | return; | 753 | return; | |
754 | 754 | |||
755 | data = TSADC_READ(sc, rks->s_data_reg) & sc->sc_data_mask; | 755 | data = TSADC_READ(sc, rks->s_data_reg) & sc->sc_data_mask; | |
756 | temp = rk_tsadc_data_to_temp(sc, data); | 756 | temp = rk_tsadc_data_to_temp(sc, data); | |
757 | 757 | |||
758 | DPRINTF("(%s:%s): temp/data %d/%u", | 758 | DPRINTF("(%s:%s): temp/data %d/%u", | |
759 | sc->sc_sme->sme_name, rks->s_data.desc, | 759 | sc->sc_sme->sme_name, rks->s_data.desc, | |
760 | temp, data); | 760 | temp, data); | |
761 | 761 | |||
762 | if (temp == sc->sc_data_mask) { | 762 | if (temp == sc->sc_data_mask) { | |
763 | edata->state = ENVSYS_SINVALID; | 763 | edata->state = ENVSYS_SINVALID; | |
764 | } else { | 764 | } else { | |
765 | edata->value_cur = temp + TEMP_uC_TO_uK; | 765 | edata->value_cur = temp + TEMP_uC_TO_uK; | |
766 | edata->state = ENVSYS_SVALID; | 766 | edata->state = ENVSYS_SVALID; | |
767 | } | 767 | } | |
768 | } | 768 | } | |
769 | 769 | |||
770 | static void | 770 | static void | |
771 | rk_tsadc_get_limits(struct sysmon_envsys *sme, | 771 | rk_tsadc_get_limits(struct sysmon_envsys *sme, | |
772 | envsys_data_t *edata, | 772 | envsys_data_t *edata, | |
773 | sysmon_envsys_lim_t *lim, | 773 | sysmon_envsys_lim_t *lim, | |
774 | uint32_t *props) | 774 | uint32_t *props) | |
775 | { | 775 | { | |
776 | struct rk_tsadc_softc *sc = sme->sme_cookie; | 776 | struct rk_tsadc_softc *sc = sme->sme_cookie; | |
777 | struct rk_tsadc_sensor *rks = rk_tsadc_edata_to_sensor(sc, edata); | 777 | struct rk_tsadc_sensor *rks = rk_tsadc_edata_to_sensor(sc, edata); | |
778 | 778 | |||
779 | if (rks == NULL) | 779 | if (rks == NULL) | |
780 | return; | 780 | return; | |
781 | 781 | |||
782 | lim->sel_critmax = rks->s_tshut + TEMP_uC_TO_uK; | 782 | lim->sel_critmax = rks->s_tshut + TEMP_uC_TO_uK; | |
783 | lim->sel_warnmax = rks->s_warn + TEMP_uC_TO_uK; | 783 | lim->sel_warnmax = rks->s_warn + TEMP_uC_TO_uK; | |
784 | 784 | |||
785 | *props = PROP_CRITMAX | PROP_WARNMAX; | 785 | *props = PROP_CRITMAX | PROP_WARNMAX; | |
786 | } | 786 | } | |
787 | 787 | |||
788 | /* XXX do something with interrupts that don't happen yet. */ | 788 | /* XXX do something with interrupts that don't happen yet. */ | |
789 | static int | 789 | static int | |
790 | rk_tsadc_intr(void *arg) | 790 | rk_tsadc_intr(void *arg) | |
791 | { | 791 | { | |
792 | struct rk_tsadc_softc * const sc = arg; | 792 | struct rk_tsadc_softc * const sc = arg; | |
793 | uint32_t val; | 793 | uint32_t val; | |
794 | 794 | |||
795 | /* XXX */ | 795 | /* XXX */ | |
796 | DPRINTF("(%s): interrupted", sc->sc_sme->sme_name); | 796 | DPRINTF("(%s): interrupted", sc->sc_sme->sme_name); | |
797 | for (unsigned n = 0; n < __arraycount(rk_tsadc_sensors); n++) { | 797 | for (unsigned n = 0; n < __arraycount(rk_tsadc_sensors); n++) { | |
798 | struct rk_tsadc_sensor *rks = &sc->sc_sensors[n]; | 798 | struct rk_tsadc_sensor *rks = &sc->sc_sensors[n]; | |
799 | 799 | |||
800 | rk_tsadc_refresh(sc->sc_sme, (envsys_data_t *)rks); | 800 | rk_tsadc_refresh(sc->sc_sme, (envsys_data_t *)rks); | |
801 | } | 801 | } | |
802 | 802 | |||
803 | /* ack interrupt */ | 803 | /* ack interrupt */ | |
804 | val = TSADC_READ(sc, TSADC_INT_PD); | 804 | val = TSADC_READ(sc, TSADC_INT_PD); | |
805 | TSADC_WRITE(sc, TSADC_INT_PD, val & ~TSADC_INT_PD_EOC_INT_PD); | 805 | TSADC_WRITE(sc, TSADC_INT_PD, val & ~TSADC_INT_PD_EOC_INT_PD); | |
806 | 806 | |||
807 | return 1; | 807 | return 1; | |
808 | } | 808 | } | |
809 | 809 | |||
810 | /* | 810 | /* | |
811 | * Convert TDASC data codes to temp and reverse. The manual only has codes | 811 | * Convert TDASC data codes to temp and reverse. The manual only has codes | |
812 | * and temperature values in 5 degC intervals, but says that interpolation | 812 | * and temperature values in 5 degC intervals, but says that interpolation | |
813 | * can be done to achieve better resolution between these values, and that | 813 | * can be done to achieve better resolution between these values, and that | |
814 | * the spacing is linear. | 814 | * the spacing is linear. | |
815 | */ | 815 | */ | |
816 | static int | 816 | static int | |
817 | rk_tsadc_data_to_temp(struct rk_tsadc_softc *sc, uint32_t data) | 817 | rk_tsadc_data_to_temp(struct rk_tsadc_softc *sc, uint32_t data) | |
818 | { | 818 | { | |
819 | unsigned i; | 819 | unsigned i; | |
820 | const rk_data *rd = sc->sc_rd; | 820 | const rk_data *rd = sc->sc_rd; | |
821 | 821 | |||
822 | if (data > rd->rd_max || data < rd->rd_min) { | 822 | if (data > rd->rd_max || data < rd->rd_min) { | |
823 | DPRINTF("data out of range (%u > %u || %u < %u)", | 823 | DPRINTF("data out of range (%u > %u || %u < %u)", | |
824 | data, rd->rd_max, data, rd->rd_min); | 824 | data, rd->rd_max, data, rd->rd_min); | |
825 | return sc->sc_data_mask; | 825 | return sc->sc_data_mask; | |
826 | } | 826 | } | |
827 | for (i = 1; i < rd->rd_size; i++) { | 827 | for (i = 1; i < rd->rd_size; i++) { | |
828 | if (rd->rd_array[i].data >= data) { | 828 | if (rd->rd_array[i].data >= data) { | |
829 | int temprange, offset; | 829 | int temprange, offset; | |
830 | uint32_t datarange, datadiff; | 830 | uint32_t datarange, datadiff; | |
831 | unsigned first, secnd; | 831 | unsigned first, secnd; | |
832 | 832 | |||
833 | if (rd->rd_array[i].data == data) | 833 | if (rd->rd_array[i].data == data) | |
834 | return rd->rd_array[i].temp; | 834 | return rd->rd_array[i].temp; | |
835 | 835 | |||
836 | /* must interpolate */ | 836 | /* must interpolate */ | |
837 | if (rd->rd_decr) { | 837 | if (rd->rd_decr) { | |
838 | first = i; | 838 | first = i; | |
839 | secnd = i+1; | 839 | secnd = i+1; | |
840 | } else { | 840 | } else { | |
841 | first = i; | 841 | first = i; | |
842 | secnd = i-1; | 842 | secnd = i-1; | |
843 | } | 843 | } | |
844 | 844 | |||
845 | temprange = rd->rd_array[first].temp - | 845 | temprange = rd->rd_array[first].temp - | |
846 | rd->rd_array[secnd].temp; | 846 | rd->rd_array[secnd].temp; | |
847 | datarange = rd->rd_array[first].data - | 847 | datarange = rd->rd_array[first].data - | |
848 | rd->rd_array[secnd].data; | 848 | rd->rd_array[secnd].data; | |
849 | datadiff = data - rd->rd_array[secnd].data; | 849 | datadiff = data - rd->rd_array[secnd].data; | |
850 | 850 | |||
851 | offset = (temprange * datadiff) / datarange; | 851 | offset = (temprange * datadiff) / datarange; | |
852 | return rd->rd_array[secnd].temp + offset; | 852 | return rd->rd_array[secnd].temp + offset; | |
853 | } | 853 | } | |
854 | } | 854 | } | |
855 | panic("didn't find range"); | 855 | panic("didn't find range"); | |
856 | } | 856 | } | |
857 | 857 | |||
858 | static uint32_t | 858 | static uint32_t | |
859 | rk_tsadc_temp_to_data(struct rk_tsadc_softc *sc, int temp) | 859 | rk_tsadc_temp_to_data(struct rk_tsadc_softc *sc, int temp) | |
860 | { | 860 | { | |
861 | unsigned i; | 861 | unsigned i; | |
862 | const rk_data *rd = sc->sc_rd; | 862 | const rk_data *rd = sc->sc_rd; | |
863 | 863 | |||
864 | for (i = 1; i < rd->rd_size; i++) { | 864 | for (i = 1; i < rd->rd_size; i++) { | |
865 | if (rd->rd_array[i].temp >= temp) { | 865 | if (rd->rd_array[i].temp >= temp) { | |
866 | int temprange, tempdiff; | 866 | int temprange, tempdiff; | |
867 | uint32_t datarange, offset; | 867 | uint32_t datarange, offset; | |
868 | unsigned first, secnd; | 868 | unsigned first, secnd; | |
869 | 869 | |||
870 | if (rd->rd_array[i].temp == temp) | 870 | if (rd->rd_array[i].temp == temp) | |
871 | return rd->rd_array[i].data; | 871 | return rd->rd_array[i].data; | |
872 | 872 | |||
873 | /* must interpolate */ | 873 | /* must interpolate */ | |
874 | if (rd->rd_decr) { | 874 | if (rd->rd_decr) { | |
875 | first = i; | 875 | first = i; | |
876 | secnd = i+1; | 876 | secnd = i+1; | |
877 | } else { | 877 | } else { | |
878 | first = i; | 878 | first = i; | |
879 | secnd = i-1; | 879 | secnd = i-1; | |
880 | } | 880 | } | |
881 | 881 | |||
882 | datarange = rd->rd_array[first].data - | 882 | datarange = rd->rd_array[first].data - | |
883 | rd->rd_array[secnd].data; | 883 | rd->rd_array[secnd].data; | |
884 | temprange = rd->rd_array[first].temp - | 884 | temprange = rd->rd_array[first].temp - | |
885 | rd->rd_array[secnd].temp; | 885 | rd->rd_array[secnd].temp; | |
886 | tempdiff = temp - rd->rd_array[secnd].temp; | 886 | tempdiff = temp - rd->rd_array[secnd].temp; | |
887 | 887 | |||
888 | offset = (datarange * tempdiff) / temprange; | 888 | offset = (datarange * tempdiff) / temprange; | |
889 | return rd->rd_array[secnd].data + offset; | 889 | return rd->rd_array[secnd].data + offset; | |
890 | } | 890 | } | |
891 | } | 891 | } | |
892 | 892 | |||
893 | return sc->sc_data_mask; | 893 | return sc->sc_data_mask; | |
894 | } | 894 | } |
--- src/sys/arch/arm/rockchip/rk_usb.c 2021/01/25 14:20:38 1.9
+++ src/sys/arch/arm/rockchip/rk_usb.c 2021/01/27 02:00:02 1.10
@@ -1,428 +1,428 @@ | @@ -1,428 +1,428 @@ | |||
1 | /* $NetBSD: rk_usb.c,v 1.9 2021/01/25 14:20:38 thorpej Exp $ */ | 1 | /* $NetBSD: rk_usb.c,v 1.10 2021/01/27 02:00:02 thorpej Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | 4 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 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 | 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 | 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 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 | 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 | * POSSIBILITY OF SUCH DAMAGE. | 26 | * POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include <sys/cdefs.h> | 29 | #include <sys/cdefs.h> | |
30 | 30 | |||
31 | __KERNEL_RCSID(0, "$NetBSD: rk_usb.c,v 1.9 2021/01/25 14:20:38 thorpej Exp $"); | 31 | __KERNEL_RCSID(0, "$NetBSD: rk_usb.c,v 1.10 2021/01/27 02:00:02 thorpej Exp $"); | |
32 | 32 | |||
33 | #include <sys/param.h> | 33 | #include <sys/param.h> | |
34 | #include <sys/bus.h> | 34 | #include <sys/bus.h> | |
35 | #include <sys/device.h> | 35 | #include <sys/device.h> | |
36 | #include <sys/intr.h> | 36 | #include <sys/intr.h> | |
37 | #include <sys/systm.h> | 37 | #include <sys/systm.h> | |
38 | #include <sys/time.h> | 38 | #include <sys/time.h> | |
39 | #include <sys/kmem.h> | 39 | #include <sys/kmem.h> | |
40 | 40 | |||
41 | #include <dev/clk/clk_backend.h> | 41 | #include <dev/clk/clk_backend.h> | |
42 | 42 | |||
43 | #include <dev/fdt/fdtvar.h> | 43 | #include <dev/fdt/fdtvar.h> | |
44 | #include <dev/fdt/syscon.h> | 44 | #include <dev/fdt/syscon.h> | |
45 | 45 | |||
46 | static int rk_usb_match(device_t, cfdata_t, void *); | 46 | static int rk_usb_match(device_t, cfdata_t, void *); | |
47 | static void rk_usb_attach(device_t, device_t, void *); | 47 | static void rk_usb_attach(device_t, device_t, void *); | |
48 | 48 | |||
49 | #define RK3328_CON0_REG 0x100 | 49 | #define RK3328_CON0_REG 0x100 | |
50 | #define RK3328_CON1_REG 0x104 | 50 | #define RK3328_CON1_REG 0x104 | |
51 | #define RK3328_CON2_REG 0x108 | 51 | #define RK3328_CON2_REG 0x108 | |
52 | #define RK3328_USBPHY_COMMONONN __BIT(4) | 52 | #define RK3328_USBPHY_COMMONONN __BIT(4) | |
53 | 53 | |||
54 | #define RK3399_GRF_USB20_PHY0_CON0_REG 0x0e450 | 54 | #define RK3399_GRF_USB20_PHY0_CON0_REG 0x0e450 | |
55 | #define RK3399_GRF_USB20_PHY1_CON0_REG 0x0e460 | 55 | #define RK3399_GRF_USB20_PHY1_CON0_REG 0x0e460 | |
56 | #define RK3399_USBPHY_COMMONONN __BIT(4) | 56 | #define RK3399_USBPHY_COMMONONN __BIT(4) | |
57 | #define RK3399_GRF_USB20_PHY0_CON1_REG 0x0e454 | 57 | #define RK3399_GRF_USB20_PHY0_CON1_REG 0x0e454 | |
58 | #define RK3399_GRF_USB20_PHY1_CON1_REG 0x0e464 | 58 | #define RK3399_GRF_USB20_PHY1_CON1_REG 0x0e464 | |
59 | #define RK3399_GRF_USB20_PHY0_CON2_REG 0x0e458 | 59 | #define RK3399_GRF_USB20_PHY0_CON2_REG 0x0e458 | |
60 | #define RK3399_GRF_USB20_PHY1_CON2_REG 0x0e468 | 60 | #define RK3399_GRF_USB20_PHY1_CON2_REG 0x0e468 | |
61 | #define RK3399_USBPHY_SUSPEND_N __BIT(1) | 61 | #define RK3399_USBPHY_SUSPEND_N __BIT(1) | |
62 | #define RK3399_USBPHY_UTMI_SEL __BIT(0) | 62 | #define RK3399_USBPHY_UTMI_SEL __BIT(0) | |
63 | 63 | |||
64 | #define RK3399_PHY_NO(_sc) ((_sc)->sc_reg == 0xe450 ? 0 : 1) | 64 | #define RK3399_PHY_NO(_sc) ((_sc)->sc_reg == 0xe450 ? 0 : 1) | |
65 | 65 | |||
66 | enum rk_usb_type { | 66 | enum rk_usb_type { | |
67 | USB_RK3328 = 1, | 67 | USB_RK3328 = 1, | |
68 | USB_RK3399, | 68 | USB_RK3399, | |
69 | }; | 69 | }; | |
70 | 70 | |||
71 | static const struct device_compatible_entry compat_data[] = { | 71 | static const struct device_compatible_entry compat_data[] = { | |
72 | { .compat = "rockchip,rk3328-usb2phy", .value = USB_RK3328 }, | 72 | { .compat = "rockchip,rk3328-usb2phy", .value = USB_RK3328 }, | |
73 | { .compat = "rockchip,rk3399-usb2phy", .value = USB_RK3399 }, | 73 | { .compat = "rockchip,rk3399-usb2phy", .value = USB_RK3399 }, | |
74 | { } | 74 | DEVICE_COMPAT_EOL | |
75 | }; | 75 | }; | |
76 | 76 | |||
77 | struct rk_usb_clk { | 77 | struct rk_usb_clk { | |
78 | struct clk base; | 78 | struct clk base; | |
79 | }; | 79 | }; | |
80 | 80 | |||
81 | struct rk_usb_softc { | 81 | struct rk_usb_softc { | |
82 | device_t sc_dev; | 82 | device_t sc_dev; | |
83 | struct syscon *sc_syscon; | 83 | struct syscon *sc_syscon; | |
84 | enum rk_usb_type sc_type; | 84 | enum rk_usb_type sc_type; | |
85 | 85 | |||
86 | struct clk_domain sc_clkdom; | 86 | struct clk_domain sc_clkdom; | |
87 | struct rk_usb_clk sc_usbclk; | 87 | struct rk_usb_clk sc_usbclk; | |
88 | 88 | |||
89 | bus_addr_t sc_reg; | 89 | bus_addr_t sc_reg; | |
90 | }; | 90 | }; | |
91 | 91 | |||
92 | CFATTACH_DECL_NEW(rk_usb, sizeof(struct rk_usb_softc), | 92 | CFATTACH_DECL_NEW(rk_usb, sizeof(struct rk_usb_softc), | |
93 | rk_usb_match, rk_usb_attach, NULL, NULL); | 93 | rk_usb_match, rk_usb_attach, NULL, NULL); | |
94 | 94 | |||
95 | static struct clk * | 95 | static struct clk * | |
96 | rk_usb_clk_get(void *priv, const char *name) | 96 | rk_usb_clk_get(void *priv, const char *name) | |
97 | { | 97 | { | |
98 | struct rk_usb_softc * const sc = priv; | 98 | struct rk_usb_softc * const sc = priv; | |
99 | 99 | |||
100 | if (strcmp(name, sc->sc_usbclk.base.name) != 0) | 100 | if (strcmp(name, sc->sc_usbclk.base.name) != 0) | |
101 | return NULL; | 101 | return NULL; | |
102 | 102 | |||
103 | return &sc->sc_usbclk.base; | 103 | return &sc->sc_usbclk.base; | |
104 | } | 104 | } | |
105 | 105 | |||
106 | static void | 106 | static void | |
107 | rk_usb_clk_put(void *priv, struct clk *clk) | 107 | rk_usb_clk_put(void *priv, struct clk *clk) | |
108 | { | 108 | { | |
109 | } | 109 | } | |
110 | 110 | |||
111 | static u_int | 111 | static u_int | |
112 | rk_usb_clk_get_rate(void *priv, struct clk *clk) | 112 | rk_usb_clk_get_rate(void *priv, struct clk *clk) | |
113 | { | 113 | { | |
114 | return 480000000; | 114 | return 480000000; | |
115 | } | 115 | } | |
116 | 116 | |||
117 | static int | 117 | static int | |
118 | rk_usb_clk_enable(void *priv, struct clk *clk) | 118 | rk_usb_clk_enable(void *priv, struct clk *clk) | |
119 | { | 119 | { | |
120 | struct rk_usb_softc * const sc = priv; | 120 | struct rk_usb_softc * const sc = priv; | |
121 | uint32_t reg, write_mask, write_val; | 121 | uint32_t reg, write_mask, write_val; | |
122 | 122 | |||
123 | switch (sc->sc_type) { | 123 | switch (sc->sc_type) { | |
124 | case USB_RK3328: | 124 | case USB_RK3328: | |
125 | reg = RK3328_CON2_REG; | 125 | reg = RK3328_CON2_REG; | |
126 | write_mask = RK3328_USBPHY_COMMONONN << 16; | 126 | write_mask = RK3328_USBPHY_COMMONONN << 16; | |
127 | write_val = 0; | 127 | write_val = 0; | |
128 | break; | 128 | break; | |
129 | case USB_RK3399: | 129 | case USB_RK3399: | |
130 | reg = RK3399_PHY_NO(sc) == 0 ? | 130 | reg = RK3399_PHY_NO(sc) == 0 ? | |
131 | RK3399_GRF_USB20_PHY0_CON0_REG : | 131 | RK3399_GRF_USB20_PHY0_CON0_REG : | |
132 | RK3399_GRF_USB20_PHY1_CON0_REG; | 132 | RK3399_GRF_USB20_PHY1_CON0_REG; | |
133 | write_mask = RK3399_USBPHY_COMMONONN << 16; | 133 | write_mask = RK3399_USBPHY_COMMONONN << 16; | |
134 | write_val = 0; | 134 | write_val = 0; | |
135 | break; | 135 | break; | |
136 | default: | 136 | default: | |
137 | return ENXIO; | 137 | return ENXIO; | |
138 | } | 138 | } | |
139 | 139 | |||
140 | syscon_lock(sc->sc_syscon); | 140 | syscon_lock(sc->sc_syscon); | |
141 | syscon_write_4(sc->sc_syscon, reg, write_mask | write_val); | 141 | syscon_write_4(sc->sc_syscon, reg, write_mask | write_val); | |
142 | syscon_unlock(sc->sc_syscon); | 142 | syscon_unlock(sc->sc_syscon); | |
143 | 143 | |||
144 | return 0; | 144 | return 0; | |
145 | } | 145 | } | |
146 | 146 | |||
147 | static int | 147 | static int | |
148 | rk_usb_clk_disable(void *priv, struct clk *clk) | 148 | rk_usb_clk_disable(void *priv, struct clk *clk) | |
149 | { | 149 | { | |
150 | struct rk_usb_softc * const sc = priv; | 150 | struct rk_usb_softc * const sc = priv; | |
151 | uint32_t reg, write_mask, write_val; | 151 | uint32_t reg, write_mask, write_val; | |
152 | 152 | |||
153 | switch (sc->sc_type) { | 153 | switch (sc->sc_type) { | |
154 | case USB_RK3328: | 154 | case USB_RK3328: | |
155 | reg = RK3328_CON2_REG; | 155 | reg = RK3328_CON2_REG; | |
156 | write_mask = RK3328_USBPHY_COMMONONN << 16; | 156 | write_mask = RK3328_USBPHY_COMMONONN << 16; | |
157 | write_val = RK3328_USBPHY_COMMONONN; | 157 | write_val = RK3328_USBPHY_COMMONONN; | |
158 | break; | 158 | break; | |
159 | case USB_RK3399: | 159 | case USB_RK3399: | |
160 | reg = RK3399_PHY_NO(sc) == 0 ? | 160 | reg = RK3399_PHY_NO(sc) == 0 ? | |
161 | RK3399_GRF_USB20_PHY0_CON0_REG : | 161 | RK3399_GRF_USB20_PHY0_CON0_REG : | |
162 | RK3399_GRF_USB20_PHY1_CON0_REG; | 162 | RK3399_GRF_USB20_PHY1_CON0_REG; | |
163 | write_mask = RK3399_USBPHY_COMMONONN << 16; | 163 | write_mask = RK3399_USBPHY_COMMONONN << 16; | |
164 | write_val = RK3399_USBPHY_COMMONONN; | 164 | write_val = RK3399_USBPHY_COMMONONN; | |
165 | break; | 165 | break; | |
166 | default: | 166 | default: | |
167 | return ENXIO; | 167 | return ENXIO; | |
168 | } | 168 | } | |
169 | 169 | |||
170 | syscon_lock(sc->sc_syscon); | 170 | syscon_lock(sc->sc_syscon); | |
171 | syscon_write_4(sc->sc_syscon, reg, write_mask | write_val); | 171 | syscon_write_4(sc->sc_syscon, reg, write_mask | write_val); | |
172 | syscon_unlock(sc->sc_syscon); | 172 | syscon_unlock(sc->sc_syscon); | |
173 | 173 | |||
174 | return 0; | 174 | return 0; | |
175 | } | 175 | } | |
176 | 176 | |||
177 | static const struct clk_funcs rk_usb_clk_funcs = { | 177 | static const struct clk_funcs rk_usb_clk_funcs = { | |
178 | .get = rk_usb_clk_get, | 178 | .get = rk_usb_clk_get, | |
179 | .put = rk_usb_clk_put, | 179 | .put = rk_usb_clk_put, | |
180 | .get_rate = rk_usb_clk_get_rate, | 180 | .get_rate = rk_usb_clk_get_rate, | |
181 | .enable = rk_usb_clk_enable, | 181 | .enable = rk_usb_clk_enable, | |
182 | .disable = rk_usb_clk_disable, | 182 | .disable = rk_usb_clk_disable, | |
183 | }; | 183 | }; | |
184 | 184 | |||
185 | static struct clk * | 185 | static struct clk * | |
186 | rk_usb_fdt_decode(device_t dev, int cc_phandle, const void *data, size_t len) | 186 | rk_usb_fdt_decode(device_t dev, int cc_phandle, const void *data, size_t len) | |
187 | { | 187 | { | |
188 | struct rk_usb_softc * const sc = device_private(dev); | 188 | struct rk_usb_softc * const sc = device_private(dev); | |
189 | 189 | |||
190 | if (len != 0) | 190 | if (len != 0) | |
191 | return NULL; | 191 | return NULL; | |
192 | 192 | |||
193 | return &sc->sc_usbclk.base; | 193 | return &sc->sc_usbclk.base; | |
194 | } | 194 | } | |
195 | 195 | |||
196 | static const struct fdtbus_clock_controller_func rk_usb_fdt_funcs = { | 196 | static const struct fdtbus_clock_controller_func rk_usb_fdt_funcs = { | |
197 | .decode = rk_usb_fdt_decode | 197 | .decode = rk_usb_fdt_decode | |
198 | }; | 198 | }; | |
199 | 199 | |||
200 | static int | 200 | static int | |
201 | rk_usb_match(device_t parent, cfdata_t cf, void *aux) | 201 | rk_usb_match(device_t parent, cfdata_t cf, void *aux) | |
202 | { | 202 | { | |
203 | struct fdt_attach_args * const faa = aux; | 203 | struct fdt_attach_args * const faa = aux; | |
204 | 204 | |||
205 | return of_match_compat_data(faa->faa_phandle, compat_data); | 205 | return of_match_compat_data(faa->faa_phandle, compat_data); | |
206 | } | 206 | } | |
207 | 207 | |||
208 | static void | 208 | static void | |
209 | rk_usb_attach(device_t parent, device_t self, void *aux) | 209 | rk_usb_attach(device_t parent, device_t self, void *aux) | |
210 | { | 210 | { | |
211 | struct rk_usb_softc * const sc = device_private(self); | 211 | struct rk_usb_softc * const sc = device_private(self); | |
212 | struct fdt_attach_args * const faa = aux; | 212 | struct fdt_attach_args * const faa = aux; | |
213 | const int phandle = faa->faa_phandle; | 213 | const int phandle = faa->faa_phandle; | |
214 | struct clk *clk; | 214 | struct clk *clk; | |
215 | int child; | 215 | int child; | |
216 | 216 | |||
217 | /* Cache the base address of this PHY so we know which instance we are */ | 217 | /* Cache the base address of this PHY so we know which instance we are */ | |
218 | if (fdtbus_get_reg(phandle, 0, &sc->sc_reg, NULL) != 0) { | 218 | if (fdtbus_get_reg(phandle, 0, &sc->sc_reg, NULL) != 0) { | |
219 | aprint_error(": couldn't get registers\n"); | 219 | aprint_error(": couldn't get registers\n"); | |
220 | return; | 220 | return; | |
221 | } | 221 | } | |
222 | 222 | |||
223 | clk = fdtbus_clock_get(phandle, "phyclk"); | 223 | clk = fdtbus_clock_get(phandle, "phyclk"); | |
224 | if (clk && clk_enable(clk) != 0) { | 224 | if (clk && clk_enable(clk) != 0) { | |
225 | aprint_error(": couldn't enable phy clock\n"); | 225 | aprint_error(": couldn't enable phy clock\n"); | |
226 | return; | 226 | return; | |
227 | } | 227 | } | |
228 | 228 | |||
229 | sc->sc_dev = self; | 229 | sc->sc_dev = self; | |
230 | sc->sc_type = of_search_compatible(phandle, compat_data)->value; | 230 | sc->sc_type = of_search_compatible(phandle, compat_data)->value; | |
231 | sc->sc_syscon = fdtbus_syscon_lookup(OF_parent(phandle)); | 231 | sc->sc_syscon = fdtbus_syscon_lookup(OF_parent(phandle)); | |
232 | if (sc->sc_syscon == NULL) { | 232 | if (sc->sc_syscon == NULL) { | |
233 | aprint_error(": couldn't get grf syscon\n"); | 233 | aprint_error(": couldn't get grf syscon\n"); | |
234 | return; | 234 | return; | |
235 | } | 235 | } | |
236 | 236 | |||
237 | const char *clkname = fdtbus_get_string(phandle, "clock-output-names"); | 237 | const char *clkname = fdtbus_get_string(phandle, "clock-output-names"); | |
238 | if (clkname == NULL) | 238 | if (clkname == NULL) | |
239 | clkname = faa->faa_name; | 239 | clkname = faa->faa_name; | |
240 | 240 | |||
241 | sc->sc_clkdom.name = device_xname(self); | 241 | sc->sc_clkdom.name = device_xname(self); | |
242 | sc->sc_clkdom.funcs = &rk_usb_clk_funcs; | 242 | sc->sc_clkdom.funcs = &rk_usb_clk_funcs; | |
243 | sc->sc_clkdom.priv = sc; | 243 | sc->sc_clkdom.priv = sc; | |
244 | sc->sc_usbclk.base.domain = &sc->sc_clkdom; | 244 | sc->sc_usbclk.base.domain = &sc->sc_clkdom; | |
245 | sc->sc_usbclk.base.name = kmem_asprintf("%s", clkname); | 245 | sc->sc_usbclk.base.name = kmem_asprintf("%s", clkname); | |
246 | clk_attach(&sc->sc_usbclk.base); | 246 | clk_attach(&sc->sc_usbclk.base); | |
247 | 247 | |||
248 | aprint_naive("\n"); | 248 | aprint_naive("\n"); | |
249 | aprint_normal(": USB2 PHY\n"); | 249 | aprint_normal(": USB2 PHY\n"); | |
250 | 250 | |||
251 | fdtbus_register_clock_controller(self, phandle, &rk_usb_fdt_funcs); | 251 | fdtbus_register_clock_controller(self, phandle, &rk_usb_fdt_funcs); | |
252 | 252 | |||
253 | for (child = OF_child(phandle); child; child = OF_peer(child)) { | 253 | for (child = OF_child(phandle); child; child = OF_peer(child)) { | |
254 | if (!fdtbus_status_okay(child)) | 254 | if (!fdtbus_status_okay(child)) | |
255 | continue; | 255 | continue; | |
256 | 256 | |||
257 | struct fdt_attach_args cfaa = *faa; | 257 | struct fdt_attach_args cfaa = *faa; | |
258 | cfaa.faa_phandle = child; | 258 | cfaa.faa_phandle = child; | |
259 | cfaa.faa_name = fdtbus_get_string(child, "name"); | 259 | cfaa.faa_name = fdtbus_get_string(child, "name"); | |
260 | cfaa.faa_quiet = false; | 260 | cfaa.faa_quiet = false; | |
261 | 261 | |||
262 | config_found(self, &cfaa, NULL); | 262 | config_found(self, &cfaa, NULL); | |
263 | } | 263 | } | |
264 | } | 264 | } | |
265 | 265 | |||
266 | /* | 266 | /* | |
267 | * USB PHY | 267 | * USB PHY | |
268 | */ | 268 | */ | |
269 | 269 | |||
270 | static int rk_usbphy_match(device_t, cfdata_t, void *); | 270 | static int rk_usbphy_match(device_t, cfdata_t, void *); | |
271 | static void rk_usbphy_attach(device_t, device_t, void *); | 271 | static void rk_usbphy_attach(device_t, device_t, void *); | |
272 | 272 | |||
273 | struct rk_usbphy_softc { | 273 | struct rk_usbphy_softc { | |
274 | device_t sc_dev; | 274 | device_t sc_dev; | |
275 | int sc_phandle; | 275 | int sc_phandle; | |
276 | struct fdtbus_regulator *sc_supply; | 276 | struct fdtbus_regulator *sc_supply; | |
277 | }; | 277 | }; | |
278 | 278 | |||
279 | CFATTACH_DECL_NEW(rk_usbphy, sizeof(struct rk_usbphy_softc), | 279 | CFATTACH_DECL_NEW(rk_usbphy, sizeof(struct rk_usbphy_softc), | |
280 | rk_usbphy_match, rk_usbphy_attach, NULL, NULL); | 280 | rk_usbphy_match, rk_usbphy_attach, NULL, NULL); | |
281 | 281 | |||
282 | static void * | 282 | static void * | |
283 | rk_usbphy_acquire(device_t dev, const void *data, size_t len) | 283 | rk_usbphy_acquire(device_t dev, const void *data, size_t len) | |
284 | { | 284 | { | |
285 | struct rk_usbphy_softc * const sc = device_private(dev); | 285 | struct rk_usbphy_softc * const sc = device_private(dev); | |
286 | 286 | |||
287 | if (len != 0) | 287 | if (len != 0) | |
288 | return NULL; | 288 | return NULL; | |
289 | 289 | |||
290 | return sc; | 290 | return sc; | |
291 | } | 291 | } | |
292 | 292 | |||
293 | static void | 293 | static void | |
294 | rk_usbphy_release(device_t dev, void *priv) | 294 | rk_usbphy_release(device_t dev, void *priv) | |
295 | { | 295 | { | |
296 | } | 296 | } | |
297 | 297 | |||
298 | static int | 298 | static int | |
299 | rk_usbphy_otg_enable(device_t dev, void *priv, bool enable) | 299 | rk_usbphy_otg_enable(device_t dev, void *priv, bool enable) | |
300 | { | 300 | { | |
301 | struct rk_usbphy_softc * const sc = device_private(dev); | 301 | struct rk_usbphy_softc * const sc = device_private(dev); | |
302 | struct rk_usb_softc * const usb_sc = device_private(device_parent(dev)); | 302 | struct rk_usb_softc * const usb_sc = device_private(device_parent(dev)); | |
303 | uint32_t reg, write_mask, write_val; | 303 | uint32_t reg, write_mask, write_val; | |
304 | int error; | 304 | int error; | |
305 | 305 | |||
306 | switch (usb_sc->sc_type) { | 306 | switch (usb_sc->sc_type) { | |
307 | case USB_RK3328: | 307 | case USB_RK3328: | |
308 | reg = RK3328_CON0_REG; | 308 | reg = RK3328_CON0_REG; | |
309 | write_mask = 0x1ffU << 16; | 309 | write_mask = 0x1ffU << 16; | |
310 | write_val = enable ? 0 : 0x1d1; | 310 | write_val = enable ? 0 : 0x1d1; | |
311 | break; | 311 | break; | |
312 | case USB_RK3399: | 312 | case USB_RK3399: | |
313 | reg = RK3399_PHY_NO(usb_sc) == 0 ? | 313 | reg = RK3399_PHY_NO(usb_sc) == 0 ? | |
314 | RK3399_GRF_USB20_PHY0_CON1_REG : | 314 | RK3399_GRF_USB20_PHY0_CON1_REG : | |
315 | RK3399_GRF_USB20_PHY1_CON1_REG; | 315 | RK3399_GRF_USB20_PHY1_CON1_REG; | |
316 | write_mask = (RK3399_USBPHY_SUSPEND_N|RK3399_USBPHY_UTMI_SEL) << 16; | 316 | write_mask = (RK3399_USBPHY_SUSPEND_N|RK3399_USBPHY_UTMI_SEL) << 16; | |
317 | write_val = enable ? 0 : RK3399_USBPHY_UTMI_SEL; | 317 | write_val = enable ? 0 : RK3399_USBPHY_UTMI_SEL; | |
318 | break; | 318 | break; | |
319 | default: | 319 | default: | |
320 | return ENXIO; | 320 | return ENXIO; | |
321 | } | 321 | } | |
322 | 322 | |||
323 | if (sc->sc_supply) { | 323 | if (sc->sc_supply) { | |
324 | error = enable ? fdtbus_regulator_enable(sc->sc_supply) : | 324 | error = enable ? fdtbus_regulator_enable(sc->sc_supply) : | |
325 | fdtbus_regulator_disable(sc->sc_supply); | 325 | fdtbus_regulator_disable(sc->sc_supply); | |
326 | if (error != 0) | 326 | if (error != 0) | |
327 | return error; | 327 | return error; | |
328 | } | 328 | } | |
329 | 329 | |||
330 | syscon_lock(usb_sc->sc_syscon); | 330 | syscon_lock(usb_sc->sc_syscon); | |
331 | syscon_write_4(usb_sc->sc_syscon, reg, write_mask | write_val); | 331 | syscon_write_4(usb_sc->sc_syscon, reg, write_mask | write_val); | |
332 | syscon_unlock(usb_sc->sc_syscon); | 332 | syscon_unlock(usb_sc->sc_syscon); | |
333 | 333 | |||
334 | return 0; | 334 | return 0; | |
335 | } | 335 | } | |
336 | 336 | |||
337 | static int | 337 | static int | |
338 | rk_usbphy_host_enable(device_t dev, void *priv, bool enable) | 338 | rk_usbphy_host_enable(device_t dev, void *priv, bool enable) | |
339 | { | 339 | { | |
340 | struct rk_usbphy_softc * const sc = device_private(dev); | 340 | struct rk_usbphy_softc * const sc = device_private(dev); | |
341 | struct rk_usb_softc * const usb_sc = device_private(device_parent(dev)); | 341 | struct rk_usb_softc * const usb_sc = device_private(device_parent(dev)); | |
342 | uint32_t reg, write_mask, write_val; | 342 | uint32_t reg, write_mask, write_val; | |
343 | int error; | 343 | int error; | |
344 | 344 | |||
345 | switch (usb_sc->sc_type) { | 345 | switch (usb_sc->sc_type) { | |
346 | case USB_RK3328: | 346 | case USB_RK3328: | |
347 | reg = RK3328_CON1_REG; | 347 | reg = RK3328_CON1_REG; | |
348 | write_mask = 0x1ffU << 16; | 348 | write_mask = 0x1ffU << 16; | |
349 | write_val = enable ? 0 : 0x1d1; | 349 | write_val = enable ? 0 : 0x1d1; | |
350 | break; | 350 | break; | |
351 | case USB_RK3399: | 351 | case USB_RK3399: | |
352 | reg = RK3399_PHY_NO(usb_sc) == 0 ? | 352 | reg = RK3399_PHY_NO(usb_sc) == 0 ? | |
353 | RK3399_GRF_USB20_PHY0_CON2_REG : | 353 | RK3399_GRF_USB20_PHY0_CON2_REG : | |
354 | RK3399_GRF_USB20_PHY1_CON2_REG; | 354 | RK3399_GRF_USB20_PHY1_CON2_REG; | |
355 | write_mask = (RK3399_USBPHY_SUSPEND_N|RK3399_USBPHY_UTMI_SEL) << 16; | 355 | write_mask = (RK3399_USBPHY_SUSPEND_N|RK3399_USBPHY_UTMI_SEL) << 16; | |
356 | write_val = enable ? 0 : RK3399_USBPHY_UTMI_SEL; | 356 | write_val = enable ? 0 : RK3399_USBPHY_UTMI_SEL; | |
357 | break; | 357 | break; | |
358 | default: | 358 | default: | |
359 | return ENXIO; | 359 | return ENXIO; | |
360 | } | 360 | } | |
361 | 361 | |||
362 | if (sc->sc_supply) { | 362 | if (sc->sc_supply) { | |
363 | error = enable ? fdtbus_regulator_enable(sc->sc_supply) : | 363 | error = enable ? fdtbus_regulator_enable(sc->sc_supply) : | |
364 | fdtbus_regulator_disable(sc->sc_supply); | 364 | fdtbus_regulator_disable(sc->sc_supply); | |
365 | if (error != 0) | 365 | if (error != 0) | |
366 | return error; | 366 | return error; | |
367 | } | 367 | } | |
368 | 368 | |||
369 | syscon_lock(usb_sc->sc_syscon); | 369 | syscon_lock(usb_sc->sc_syscon); | |
370 | syscon_write_4(usb_sc->sc_syscon, reg, write_mask | write_val); | 370 | syscon_write_4(usb_sc->sc_syscon, reg, write_mask | write_val); | |
371 | syscon_unlock(usb_sc->sc_syscon); | 371 | syscon_unlock(usb_sc->sc_syscon); | |
372 | 372 | |||
373 | return 0; | 373 | return 0; | |
374 | } | 374 | } | |
375 | 375 | |||
376 | const struct fdtbus_phy_controller_func rk_usbphy_otg_funcs = { | 376 | const struct fdtbus_phy_controller_func rk_usbphy_otg_funcs = { | |
377 | .acquire = rk_usbphy_acquire, | 377 | .acquire = rk_usbphy_acquire, | |
378 | .release = rk_usbphy_release, | 378 | .release = rk_usbphy_release, | |
379 | .enable = rk_usbphy_otg_enable, | 379 | .enable = rk_usbphy_otg_enable, | |
380 | }; | 380 | }; | |
381 | 381 | |||
382 | const struct fdtbus_phy_controller_func rk_usbphy_host_funcs = { | 382 | const struct fdtbus_phy_controller_func rk_usbphy_host_funcs = { | |
383 | .acquire = rk_usbphy_acquire, | 383 | .acquire = rk_usbphy_acquire, | |
384 | .release = rk_usbphy_release, | 384 | .release = rk_usbphy_release, | |
385 | .enable = rk_usbphy_host_enable, | 385 | .enable = rk_usbphy_host_enable, | |
386 | }; | 386 | }; | |
387 | 387 | |||
388 | static int | 388 | static int | |
389 | rk_usbphy_match(device_t parent, cfdata_t cf, void *aux) | 389 | rk_usbphy_match(device_t parent, cfdata_t cf, void *aux) | |
390 | { | 390 | { | |
391 | struct fdt_attach_args * const faa = aux; | 391 | struct fdt_attach_args * const faa = aux; | |
392 | const int phandle = faa->faa_phandle; | 392 | const int phandle = faa->faa_phandle; | |
393 | const char *name = fdtbus_get_string(phandle, "name"); | 393 | const char *name = fdtbus_get_string(phandle, "name"); | |
394 | 394 | |||
395 | if (strcmp(name, "otg-port") == 0 || strcmp(name, "host-port") == 0) | 395 | if (strcmp(name, "otg-port") == 0 || strcmp(name, "host-port") == 0) | |
396 | return 1; | 396 | return 1; | |
397 | 397 | |||
398 | return 0; | 398 | return 0; | |
399 | } | 399 | } | |
400 | 400 | |||
401 | static void | 401 | static void | |
402 | rk_usbphy_attach(device_t parent, device_t self, void *aux) | 402 | rk_usbphy_attach(device_t parent, device_t self, void *aux) | |
403 | { | 403 | { | |
404 | struct rk_usbphy_softc * const sc = device_private(self); | 404 | struct rk_usbphy_softc * const sc = device_private(self); | |
405 | struct fdt_attach_args * const faa = aux; | 405 | struct fdt_attach_args * const faa = aux; | |
406 | const int phandle = faa->faa_phandle; | 406 | const int phandle = faa->faa_phandle; | |
407 | const char *name = fdtbus_get_string(phandle, "name"); | 407 | const char *name = fdtbus_get_string(phandle, "name"); | |
408 | 408 | |||
409 | sc->sc_dev = self; | 409 | sc->sc_dev = self; | |
410 | sc->sc_phandle = phandle; | 410 | sc->sc_phandle = phandle; | |
411 | if (of_hasprop(phandle, "phy-supply")) { | 411 | if (of_hasprop(phandle, "phy-supply")) { | |
412 | sc->sc_supply = fdtbus_regulator_acquire(phandle, "phy-supply"); | 412 | sc->sc_supply = fdtbus_regulator_acquire(phandle, "phy-supply"); | |
413 | if (sc->sc_supply == NULL) { | 413 | if (sc->sc_supply == NULL) { | |
414 | aprint_error(": couldn't acquire regulator\n"); | 414 | aprint_error(": couldn't acquire regulator\n"); | |
415 | return; | 415 | return; | |
416 | } | 416 | } | |
417 | } | 417 | } | |
418 | 418 | |||
419 | aprint_naive("\n"); | 419 | aprint_naive("\n"); | |
420 | 420 | |||
421 | if (strcmp(name, "otg-port") == 0) { | 421 | if (strcmp(name, "otg-port") == 0) { | |
422 | aprint_normal(": USB2 OTG port\n"); | 422 | aprint_normal(": USB2 OTG port\n"); | |
423 | fdtbus_register_phy_controller(self, phandle, &rk_usbphy_otg_funcs); | 423 | fdtbus_register_phy_controller(self, phandle, &rk_usbphy_otg_funcs); | |
424 | } else if (strcmp(name, "host-port") == 0) { | 424 | } else if (strcmp(name, "host-port") == 0) { | |
425 | aprint_normal(": USB2 host port\n"); | 425 | aprint_normal(": USB2 host port\n"); | |
426 | fdtbus_register_phy_controller(self, phandle, &rk_usbphy_host_funcs); | 426 | fdtbus_register_phy_controller(self, phandle, &rk_usbphy_host_funcs); | |
427 | } | 427 | } | |
428 | } | 428 | } |