source: mainline/uspace/drv/infrastructure/rootamdm37x/rootamdm37x.c@ d27a9c8f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d27a9c8f was d27a9c8f, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

rootamdm37x: Remove pio_read casts.

  • Property mode set to 100644
File size: 11.4 KB
Line 
1/*
2 * Copyright (c) 2012 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @defgroup root_amdm37x TI AM/DM37x platform driver.
31 * @brief HelenOS TI AM/DM37x platform driver.
32 * @{
33 */
34
35/** @file
36 */
37#define _DDF_DATA_IMPLANT
38
39#define DEBUG_CM 1
40
41#include <ddf/driver.h>
42#include <ddf/log.h>
43#include <errno.h>
44#include <ops/hw_res.h>
45#include <stdio.h>
46#include <ddi.h>
47
48#include "uhh.h"
49#include "usbtll.h"
50#include "cm/core.h"
51#include "cm/clock_control.h"
52#include "cm/usbhost.h"
53
54#define NAME "rootamdm37x"
55
56typedef struct {
57 uhh_regs_t *uhh;
58 tll_regs_t *tll;
59 struct {
60 core_cm_regs_t *core;
61 clock_control_cm_regs_t *clocks;
62 usbhost_cm_regs_t *usbhost;
63 } cm;
64} amdm37x_t;
65
66static void log(const volatile void *place, uint32_t val, volatile void* base, size_t size, void *data, bool write)
67{
68 printf("PIO %s: %p(%p) %#"PRIx32"\n", write ? "WRITE" : "READ",
69 (place - base) + data, place, val);
70}
71
72static int amdm37x_hw_access_init(amdm37x_t *device)
73{
74 assert(device);
75 int ret = EOK;
76
77 ret = pio_enable((void*)USBHOST_CM_BASE_ADDRESS, USBHOST_CM_SIZE,
78 (void**)&device->cm.usbhost);
79 if (ret != EOK)
80 return ret;
81
82 ret = pio_enable((void*)CORE_CM_BASE_ADDRESS, CORE_CM_SIZE,
83 (void**)&device->cm.core);
84 if (ret != EOK)
85 return ret;
86
87 ret = pio_enable((void*)CLOCK_CONTROL_CM_BASE_ADDRESS,
88 CLOCK_CONTROL_CM_SIZE, (void**)&device->cm.clocks);
89 if (ret != EOK)
90 return ret;
91
92 ret = pio_enable((void*)AMDM37x_USBTLL_BASE_ADDRESS,
93 AMDM37x_USBTLL_SIZE, (void**)&device->tll);
94 if (ret != EOK)
95 return ret;
96
97 ret = pio_enable((void*)AMDM37x_UHH_BASE_ADDRESS,
98 AMDM37x_UHH_SIZE, (void**)&device->uhh);
99 if (ret != EOK)
100 return ret;
101
102 if (DEBUG_CM) {
103 pio_trace_enable(device->tll, AMDM37x_USBTLL_SIZE, log, (void*)AMDM37x_USBTLL_BASE_ADDRESS);
104 pio_trace_enable(device->cm.clocks, CLOCK_CONTROL_CM_SIZE, log, (void*)CLOCK_CONTROL_CM_BASE_ADDRESS);
105 pio_trace_enable(device->cm.core, CORE_CM_SIZE, log, (void*)CORE_CM_BASE_ADDRESS);
106 pio_trace_enable(device->cm.usbhost, USBHOST_CM_SIZE, log, (void*)USBHOST_CM_BASE_ADDRESS);
107 pio_trace_enable(device->uhh, AMDM37x_UHH_SIZE, log, (void*)AMDM37x_UHH_BASE_ADDRESS);
108 }
109 return EOK;
110}
111
112/** Set DPLL3,4,5 to autoidle
113 * @param device Register map.
114 */
115static void dpll_autoidle(amdm37x_t *device)
116{
117 assert(device);
118 /* Set DPLL3 to automatic */
119 pio_change_32(&device->cm.clocks->autoidle_pll,
120 CLOCK_CONTROL_CM_AUTOIDLE_PLL_AUTO_CORE_DPLL_AUTOMATIC,
121 CLOCK_CONTROL_CM_AUTOIDLE_PLL_AUTO_CORE_DPLL_MASK, 5);
122
123 /* Set DPLL4 to automatic */
124 pio_change_32(&device->cm.clocks->autoidle_pll,
125 CLOCK_CONTROL_CM_AUTOIDLE_PLL_AUTO_PERIPH_DPLL_AUTOMATIC,
126 CLOCK_CONTROL_CM_AUTOIDLE_PLL_AUTO_PERIPH_DPLL_MASK, 5);
127
128 /* Set DPLL5 to automatic */
129 pio_change_32(&device->cm.clocks->autoidle2_pll,
130 CLOCK_CONTROL_CM_AUTOIDLE2_PLL_AUTO_PERIPH2_DPLL_AUTOMATIC,
131 CLOCK_CONTROL_CM_AUTOIDLE2_PLL_AUTO_PERIPH2_DPLL_MASK, 5);
132}
133
134/** Enable/disable function and interface clocks for USBTLL and USBHOST.
135 * @param device Register map.
136 * @param on True to swoitch clocks on.
137 */
138static void usb_clocks_enable(amdm37x_t *device, bool on)
139{
140 if (on) {
141 /* Enable interface and function clock for USB TLL */
142 pio_set_32(&device->cm.core->fclken3,
143 CORE_CM_FCLKEN3_EN_USBTLL_FLAG, 5);
144 pio_set_32(&device->cm.core->iclken3,
145 CORE_CM_ICLKEN3_EN_USBTLL_FLAG, 5);
146
147 /* Enable interface and function clock for USB hosts */
148 pio_set_32(&device->cm.usbhost->fclken,
149 USBHOST_CM_FCLKEN_EN_USBHOST1_FLAG |
150 USBHOST_CM_FCLKEN_EN_USBHOST2_FLAG, 5);
151 pio_set_32(&device->cm.usbhost->iclken,
152 USBHOST_CM_ICLKEN_EN_USBHOST, 5);
153
154 if (DEBUG_CM) {
155 printf("DPLL5 (and everything else) should be on: %"
156 PRIx32" %"PRIx32".\n",
157 pio_read_32(&device->cm.clocks->idlest_ckgen),
158 pio_read_32(&device->cm.clocks->idlest2_ckgen));
159 }
160 } else {
161 /* Disable interface and function clock for USB hosts */
162 pio_clear_32(&device->cm.usbhost->iclken,
163 USBHOST_CM_ICLKEN_EN_USBHOST, 5);
164 pio_clear_32(&device->cm.usbhost->fclken,
165 USBHOST_CM_FCLKEN_EN_USBHOST1_FLAG |
166 USBHOST_CM_FCLKEN_EN_USBHOST2_FLAG, 5);
167
168 /* Disable interface and function clock for USB TLL */
169 pio_clear_32(&device->cm.core->iclken3,
170 CORE_CM_ICLKEN3_EN_USBTLL_FLAG, 5);
171 pio_clear_32(&device->cm.core->fclken3,
172 CORE_CM_FCLKEN3_EN_USBTLL_FLAG, 5);
173 }
174}
175
176/** Initialize USB TLL port connections.
177 *
178 * Different modes are on page 3312 of the Manual Figure 22-34.
179 * Select mode than can operate in FS/LS.
180 */
181static int usb_tll_init(amdm37x_t *device)
182{
183 /* Reset USB TLL */
184 pio_set_32(&device->tll->sysconfig, TLL_SYSCONFIG_SOFTRESET_FLAG, 5);
185 ddf_msg(LVL_DEBUG2, "Waiting for USB TLL reset");
186 while (!(pio_read_32(&device->tll->sysstatus) & TLL_SYSSTATUS_RESET_DONE_FLAG));
187 ddf_msg(LVL_DEBUG, "USB TLL Reset done.");
188
189 /* Setup idle mode (smart idle) */
190 pio_change_32(&device->tll->sysconfig,
191 TLL_SYSCONFIG_CLOCKACTIVITY_FLAG | TLL_SYSCONFIG_AUTOIDLE_FLAG |
192 TLL_SYSCONFIG_SIDLE_MODE_SMART, TLL_SYSCONFIG_SIDLE_MODE_MASK, 5);
193
194 /* Smart idle for UHH */
195 pio_change_32(&device->uhh->sysconfig,
196 UHH_SYSCONFIG_CLOCKACTIVITY_FLAG | UHH_SYSCONFIG_AUTOIDLE_FLAG |
197 UHH_SYSCONFIG_SIDLE_MODE_SMART, UHH_SYSCONFIG_SIDLE_MODE_MASK, 5);
198
199 /* Set all ports to go through TLL(UTMI)
200 * Direct connection can only work in HS mode */
201 pio_set_32(&device->uhh->hostconfig,
202 UHH_HOSTCONFIG_P1_ULPI_BYPASS_FLAG |
203 UHH_HOSTCONFIG_P2_ULPI_BYPASS_FLAG |
204 UHH_HOSTCONFIG_P3_ULPI_BYPASS_FLAG, 5);
205
206 /* What is this? */
207 pio_set_32(&device->tll->shared_conf, TLL_SHARED_CONF_FCLK_IS_ON_FLAG, 5);
208
209 for (unsigned i = 0; i < 3; ++i) {
210 /* Serial mode is the only one capable of FS/LS operation.
211 * Select FS/LS mode, no idea what the difference is
212 * one of bidirectional modes might be good choice
213 * 2 = 3pin bidi phy. */
214 pio_change_32(&device->tll->channel_conf[i],
215 TLL_CHANNEL_CONF_CHANMODE_UTMI_SERIAL_MODE |
216 TLL_CHANNEL_CONF_FSLSMODE_3PIN_BIDI_PHY,
217 TLL_CHANNEL_CONF_CHANMODE_MASK |
218 TLL_CHANNEL_CONF_FSLSMODE_MASK, 5);
219 }
220 return EOK;
221}
222
223typedef struct {
224 hw_resource_list_t hw_resources;
225} rootamdm37x_fun_t;
226
227#define OHCI_BASE_ADDRESS 0x48064400
228#define OHCI_SIZE 1024
229#define EHCI_BASE_ADDRESS 0x48064800
230#define EHCI_SIZE 1024
231
232static hw_resource_t ohci_res[] = {
233 {
234 .type = MEM_RANGE,
235 /* See amdm37x TRM page. 3316 for these values */
236 .res.io_range = {
237 .address = OHCI_BASE_ADDRESS,
238 .size = OHCI_SIZE,
239 .endianness = LITTLE_ENDIAN
240 },
241 },
242 {
243 .type = INTERRUPT,
244 .res.interrupt = { .irq = 76 },
245 },
246};
247
248static const rootamdm37x_fun_t ohci = {
249 .hw_resources = {
250 .resources = ohci_res,
251 .count = sizeof(ohci_res)/sizeof(ohci_res[0]),
252 }
253};
254
255static hw_resource_t ehci_res[] = {
256 {
257 .type = MEM_RANGE,
258 /* See amdm37x TRM page. 3316 for these values */
259 .res.io_range = {
260 .address = EHCI_BASE_ADDRESS,
261 .size = EHCI_SIZE,
262 .endianness = LITTLE_ENDIAN
263 },
264 },
265 {
266 .type = INTERRUPT,
267 .res.interrupt = { .irq = 77 },
268 },
269};
270
271static const rootamdm37x_fun_t ehci = {
272 .hw_resources = {
273 .resources = ehci_res,
274 .count = sizeof(ehci_res) / sizeof(ehci_res[0]),
275 }
276};
277
278static hw_resource_list_t *rootamdm37x_get_resources(ddf_fun_t *fnode);
279static bool rootamdm37x_enable_interrupt(ddf_fun_t *fun);
280
281static hw_res_ops_t fun_hw_res_ops = {
282 .get_resource_list = &rootamdm37x_get_resources,
283 .enable_interrupt = &rootamdm37x_enable_interrupt,
284};
285
286static ddf_dev_ops_t rootamdm37x_fun_ops =
287{
288 .interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops
289};
290
291static bool rootamdm37x_add_fun(ddf_dev_t *dev, const char *name,
292 const char *str_match_id, const rootamdm37x_fun_t *fun)
293{
294 ddf_msg(LVL_DEBUG, "Adding new function '%s'.", name);
295
296 /* Create new device function. */
297 ddf_fun_t *fnode = ddf_fun_create(dev, fun_inner, name);
298 if (fnode == NULL)
299 return ENOMEM;
300
301
302 /* Add match id */
303 if (ddf_fun_add_match_id(fnode, str_match_id, 100) != EOK) {
304 ddf_fun_destroy(fnode);
305 return false;
306 }
307
308 /* Set provided operations to the device. */
309 ddf_fun_data_implant(fnode, (void*)fun);
310 ddf_fun_set_ops(fnode, &rootamdm37x_fun_ops);
311
312 /* Register function. */
313 if (ddf_fun_bind(fnode) != EOK) {
314 ddf_msg(LVL_ERROR, "Failed binding function %s.", name);
315 // TODO This will try to free our data!
316 ddf_fun_destroy(fnode);
317 return false;
318 }
319
320 return true;
321}
322
323/** Add the root device.
324 *
325 * @param dev Device which is root of the whole device tree
326 * (both of HW and pseudo devices).
327 *
328 * @return Zero on success, negative error number otherwise.
329 *
330 */
331static int rootamdm37x_dev_add(ddf_dev_t *dev)
332{
333 assert(dev);
334 amdm37x_t *device = ddf_dev_data_alloc(dev, sizeof(amdm37x_t));
335 if (!device)
336 return ENOMEM;
337 int ret = amdm37x_hw_access_init(device);
338 if (ret != EOK) {
339 ddf_msg(LVL_FATAL, "Failed to setup hw access!.\n");
340 return ret;
341 }
342
343 /* Set dplls to automatic */
344 dpll_autoidle(device);
345
346 /* Enable function and interface clocks */
347 usb_clocks_enable(device, true);
348
349 /* Init TLL */
350 ret = usb_tll_init(device);
351 if (ret != EOK) {
352 ddf_msg(LVL_FATAL, "Failed to init USB TLL!.\n");
353 usb_clocks_enable(device, false);
354 return ret;
355 }
356
357 /* Register functions */
358 if (!rootamdm37x_add_fun(dev, "ohci", "usb/host=ohci", &ohci))
359 ddf_msg(LVL_ERROR, "Failed to add OHCI function for "
360 "BeagleBoard-xM platform.");
361 if (!rootamdm37x_add_fun(dev, "ehci", "usb/host=ehci", &ehci))
362 ddf_msg(LVL_ERROR, "Failed to add EHCI function for "
363 "BeagleBoard-xM platform.");
364
365 return EOK;
366}
367
368/** The root device driver's standard operations. */
369static driver_ops_t rootamdm37x_ops = {
370 .dev_add = &rootamdm37x_dev_add
371};
372
373/** The root device driver structure. */
374static driver_t rootamdm37x_driver = {
375 .name = NAME,
376 .driver_ops = &rootamdm37x_ops
377};
378
379static hw_resource_list_t *rootamdm37x_get_resources(ddf_fun_t *fnode)
380{
381 rootamdm37x_fun_t *fun = ddf_fun_data_get(fnode);
382 assert(fun != NULL);
383 return &fun->hw_resources;
384}
385
386static bool rootamdm37x_enable_interrupt(ddf_fun_t *fun)
387{
388 /* TODO */
389 return false;
390}
391
392int main(int argc, char *argv[])
393{
394 printf("%s: HelenOS AM/DM37x(OMAP37x) platform driver\n", NAME);
395 ddf_log_init(NAME);
396 return ddf_driver_main(&rootamdm37x_driver);
397}
398
399/**
400 * @}
401 */
Note: See TracBrowser for help on using the repository browser.