aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c143
1 files changed, 122 insertions, 21 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e3f0ecaf87dd..8a1b5e0bad40 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -399,7 +399,7 @@ static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v)
399} 399}
400 400
401/** 401/**
402 * _set_softreset: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v 402 * _set_softreset: set OCP_SYSCONFIG.SOFTRESET bit in @v
403 * @oh: struct omap_hwmod * 403 * @oh: struct omap_hwmod *
404 * @v: pointer to register contents to modify 404 * @v: pointer to register contents to modify
405 * 405 *
@@ -427,6 +427,36 @@ static int _set_softreset(struct omap_hwmod *oh, u32 *v)
427} 427}
428 428
429/** 429/**
430 * _clear_softreset: clear OCP_SYSCONFIG.SOFTRESET bit in @v
431 * @oh: struct omap_hwmod *
432 * @v: pointer to register contents to modify
433 *
434 * Clear the SOFTRESET bit in @v for hwmod @oh. Returns -EINVAL upon
435 * error or 0 upon success.
436 */
437static int _clear_softreset(struct omap_hwmod *oh, u32 *v)
438{
439 u32 softrst_mask;
440
441 if (!oh->class->sysc ||
442 !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
443 return -EINVAL;
444
445 if (!oh->class->sysc->sysc_fields) {
446 WARN(1,
447 "omap_hwmod: %s: sysc_fields absent for sysconfig class\n",
448 oh->name);
449 return -EINVAL;
450 }
451
452 softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift);
453
454 *v &= ~softrst_mask;
455
456 return 0;
457}
458
459/**
430 * _wait_softreset_complete - wait for an OCP softreset to complete 460 * _wait_softreset_complete - wait for an OCP softreset to complete
431 * @oh: struct omap_hwmod * to wait on 461 * @oh: struct omap_hwmod * to wait on
432 * 462 *
@@ -785,6 +815,7 @@ static int _init_interface_clks(struct omap_hwmod *oh)
785 pr_warning("omap_hwmod: %s: cannot clk_get interface_clk %s\n", 815 pr_warning("omap_hwmod: %s: cannot clk_get interface_clk %s\n",
786 oh->name, os->clk); 816 oh->name, os->clk);
787 ret = -EINVAL; 817 ret = -EINVAL;
818 continue;
788 } 819 }
789 os->_clk = c; 820 os->_clk = c;
790 /* 821 /*
@@ -821,6 +852,7 @@ static int _init_opt_clks(struct omap_hwmod *oh)
821 pr_warning("omap_hwmod: %s: cannot clk_get opt_clk %s\n", 852 pr_warning("omap_hwmod: %s: cannot clk_get opt_clk %s\n",
822 oh->name, oc->clk); 853 oh->name, oc->clk);
823 ret = -EINVAL; 854 ret = -EINVAL;
855 continue;
824 } 856 }
825 oc->_clk = c; 857 oc->_clk = c;
826 /* 858 /*
@@ -1911,6 +1943,12 @@ static int _ocp_softreset(struct omap_hwmod *oh)
1911 ret = _set_softreset(oh, &v); 1943 ret = _set_softreset(oh, &v);
1912 if (ret) 1944 if (ret)
1913 goto dis_opt_clks; 1945 goto dis_opt_clks;
1946
1947 _write_sysconfig(v, oh);
1948 ret = _clear_softreset(oh, &v);
1949 if (ret)
1950 goto dis_opt_clks;
1951
1914 _write_sysconfig(v, oh); 1952 _write_sysconfig(v, oh);
1915 1953
1916 if (oh->class->sysc->srst_udelay) 1954 if (oh->class->sysc->srst_udelay)
@@ -2326,38 +2364,80 @@ static int _shutdown(struct omap_hwmod *oh)
2326 return 0; 2364 return 0;
2327} 2365}
2328 2366
2367static int of_dev_find_hwmod(struct device_node *np,
2368 struct omap_hwmod *oh)
2369{
2370 int count, i, res;
2371 const char *p;
2372
2373 count = of_property_count_strings(np, "ti,hwmods");
2374 if (count < 1)
2375 return -ENODEV;
2376
2377 for (i = 0; i < count; i++) {
2378 res = of_property_read_string_index(np, "ti,hwmods",
2379 i, &p);
2380 if (res)
2381 continue;
2382 if (!strcmp(p, oh->name)) {
2383 pr_debug("omap_hwmod: dt %s[%i] uses hwmod %s\n",
2384 np->name, i, oh->name);
2385 return i;
2386 }
2387 }
2388
2389 return -ENODEV;
2390}
2391
2329/** 2392/**
2330 * of_dev_hwmod_lookup - look up needed hwmod from dt blob 2393 * of_dev_hwmod_lookup - look up needed hwmod from dt blob
2331 * @np: struct device_node * 2394 * @np: struct device_node *
2332 * @oh: struct omap_hwmod * 2395 * @oh: struct omap_hwmod *
2396 * @index: index of the entry found
2397 * @found: struct device_node * found or NULL
2333 * 2398 *
2334 * Parse the dt blob and find out needed hwmod. Recursive function is 2399 * Parse the dt blob and find out needed hwmod. Recursive function is
2335 * implemented to take care hierarchical dt blob parsing. 2400 * implemented to take care hierarchical dt blob parsing.
2336 * Return: The device node on success or NULL on failure. 2401 * Return: Returns 0 on success, -ENODEV when not found.
2337 */ 2402 */
2338static struct device_node *of_dev_hwmod_lookup(struct device_node *np, 2403static int of_dev_hwmod_lookup(struct device_node *np,
2339 struct omap_hwmod *oh) 2404 struct omap_hwmod *oh,
2405 int *index,
2406 struct device_node **found)
2340{ 2407{
2341 struct device_node *np0 = NULL, *np1 = NULL; 2408 struct device_node *np0 = NULL;
2342 const char *p; 2409 int res;
2410
2411 res = of_dev_find_hwmod(np, oh);
2412 if (res >= 0) {
2413 *found = np;
2414 *index = res;
2415 return 0;
2416 }
2343 2417
2344 for_each_child_of_node(np, np0) { 2418 for_each_child_of_node(np, np0) {
2345 if (of_find_property(np0, "ti,hwmods", NULL)) { 2419 struct device_node *fc;
2346 p = of_get_property(np0, "ti,hwmods", NULL); 2420 int i;
2347 if (!strcmp(p, oh->name)) 2421
2348 return np0; 2422 res = of_dev_hwmod_lookup(np0, oh, &i, &fc);
2349 np1 = of_dev_hwmod_lookup(np0, oh); 2423 if (res == 0) {
2350 if (np1) 2424 *found = fc;
2351 return np1; 2425 *index = i;
2426 return 0;
2352 } 2427 }
2353 } 2428 }
2354 return NULL; 2429
2430 *found = NULL;
2431 *index = 0;
2432
2433 return -ENODEV;
2355} 2434}
2356 2435
2357/** 2436/**
2358 * _init_mpu_rt_base - populate the virtual address for a hwmod 2437 * _init_mpu_rt_base - populate the virtual address for a hwmod
2359 * @oh: struct omap_hwmod * to locate the virtual address 2438 * @oh: struct omap_hwmod * to locate the virtual address
2360 * @data: (unused, caller should pass NULL) 2439 * @data: (unused, caller should pass NULL)
2440 * @index: index of the reg entry iospace in device tree
2361 * @np: struct device_node * of the IP block's device node in the DT data 2441 * @np: struct device_node * of the IP block's device node in the DT data
2362 * 2442 *
2363 * Cache the virtual address used by the MPU to access this IP block's 2443 * Cache the virtual address used by the MPU to access this IP block's
@@ -2368,7 +2448,7 @@ static struct device_node *of_dev_hwmod_lookup(struct device_node *np,
2368 * -ENXIO on absent or invalid register target address space. 2448 * -ENXIO on absent or invalid register target address space.
2369 */ 2449 */
2370static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data, 2450static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
2371 struct device_node *np) 2451 int index, struct device_node *np)
2372{ 2452{
2373 struct omap_hwmod_addr_space *mem; 2453 struct omap_hwmod_addr_space *mem;
2374 void __iomem *va_start = NULL; 2454 void __iomem *va_start = NULL;
@@ -2390,13 +2470,17 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
2390 if (!np) 2470 if (!np)
2391 return -ENXIO; 2471 return -ENXIO;
2392 2472
2393 va_start = of_iomap(np, oh->mpu_rt_idx); 2473 va_start = of_iomap(np, index + oh->mpu_rt_idx);
2394 } else { 2474 } else {
2395 va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); 2475 va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
2396 } 2476 }
2397 2477
2398 if (!va_start) { 2478 if (!va_start) {
2399 pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name); 2479 if (mem)
2480 pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name);
2481 else
2482 pr_err("omap_hwmod: %s: Missing dt reg%i for %s\n",
2483 oh->name, index, np->full_name);
2400 return -ENXIO; 2484 return -ENXIO;
2401 } 2485 }
2402 2486
@@ -2422,17 +2506,29 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
2422 */ 2506 */
2423static int __init _init(struct omap_hwmod *oh, void *data) 2507static int __init _init(struct omap_hwmod *oh, void *data)
2424{ 2508{
2425 int r; 2509 int r, index;
2426 struct device_node *np = NULL; 2510 struct device_node *np = NULL;
2427 2511
2428 if (oh->_state != _HWMOD_STATE_REGISTERED) 2512 if (oh->_state != _HWMOD_STATE_REGISTERED)
2429 return 0; 2513 return 0;
2430 2514
2431 if (of_have_populated_dt()) 2515 if (of_have_populated_dt()) {
2432 np = of_dev_hwmod_lookup(of_find_node_by_name(NULL, "ocp"), oh); 2516 struct device_node *bus;
2517
2518 bus = of_find_node_by_name(NULL, "ocp");
2519 if (!bus)
2520 return -ENODEV;
2521
2522 r = of_dev_hwmod_lookup(bus, oh, &index, &np);
2523 if (r)
2524 pr_debug("omap_hwmod: %s missing dt data\n", oh->name);
2525 else if (np && index)
2526 pr_warn("omap_hwmod: %s using broken dt data from %s\n",
2527 oh->name, np->name);
2528 }
2433 2529
2434 if (oh->class->sysc) { 2530 if (oh->class->sysc) {
2435 r = _init_mpu_rt_base(oh, NULL, np); 2531 r = _init_mpu_rt_base(oh, NULL, index, np);
2436 if (r < 0) { 2532 if (r < 0) {
2437 WARN(1, "omap_hwmod: %s: doesn't have mpu register target base\n", 2533 WARN(1, "omap_hwmod: %s: doesn't have mpu register target base\n",
2438 oh->name); 2534 oh->name);
@@ -3169,6 +3265,11 @@ int omap_hwmod_softreset(struct omap_hwmod *oh)
3169 goto error; 3265 goto error;
3170 _write_sysconfig(v, oh); 3266 _write_sysconfig(v, oh);
3171 3267
3268 ret = _clear_softreset(oh, &v);
3269 if (ret)
3270 goto error;
3271 _write_sysconfig(v, oh);
3272
3172error: 3273error:
3173 return ret; 3274 return ret;
3174} 3275}