^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * omap_hwmod implementation for OMAP2/3/4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009-2011 Nokia Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2011-2012 Texas Instruments, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Paul Walmsley, Benoît Cousson, Kevin Hilman
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Created in collaboration with (alphabetical order): Thara Gopinath,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Tony Lindgren, Rajendra Nayak, Vikram Pandita, Sakari Poussa, Anand
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Sawant, Santosh Shilimkar, Richard Woodruff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Introduction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * ------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * One way to view an OMAP SoC is as a collection of largely unrelated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * IP blocks connected by interconnects. The IP blocks include
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * devices such as ARM processors, audio serial interfaces, UARTs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * etc. Some of these devices, like the DSP, are created by TI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * others, like the SGX, largely originate from external vendors. In
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * TI's documentation, on-chip devices are referred to as "OMAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * modules." Some of these IP blocks are identical across several
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * OMAP versions. Others are revised frequently.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * These OMAP modules are tied together by various interconnects.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * Most of the address and data flow between modules is via OCP-based
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * interconnects such as the L3 and L4 buses; but there are other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * interconnects that distribute the hardware clock tree, handle idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * and reset signaling, supply power, and connect the modules to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * various pads or balls on the OMAP package.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * OMAP hwmod provides a consistent way to describe the on-chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * hardware blocks and their integration into the rest of the chip.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * This description can be automatically generated from the TI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * hardware database. OMAP hwmod provides a standard, consistent API
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * to reset, enable, idle, and disable these hardware blocks. And
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * hwmod provides a way for other core code, such as the Linux device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * code or the OMAP power management and address space mapping code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * to query the hardware database.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * Using hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * -----------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * Drivers won't call hwmod functions directly. That is done by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * omap_device code, and in rare occasions, by custom integration code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * in arch/arm/ *omap*. The omap_device code includes functions to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * build a struct platform_device using omap_hwmod data, and that is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * currently how hwmod data is communicated to drivers and to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * Linux driver model. Most drivers will call omap_hwmod functions only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * indirectly, via pm_runtime*() functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * From a layering perspective, here is where the OMAP hwmod code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * fits into the kernel software stack:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * +-------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * | Device driver code |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * | (e.g., drivers/) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * +-------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * | Linux driver model |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * | (platform_device / |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * | platform_driver data/code) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * +-------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * | OMAP core-driver integration |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * |(arch/arm/mach-omap2/devices.c)|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * +-------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * | omap_device code |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * | (../plat-omap/omap_device.c) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * +-------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * ----> | omap_hwmod code/data | <-----
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * | (../mach-omap2/omap_hwmod*) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * +-------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * | OMAP clock/PRCM/register fns |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * | ({read,write}l_relaxed, clk*) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * +-------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * Device drivers should not contain any OMAP-specific code or data in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * them. They should only contain code to operate the IP block that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * the driver is responsible for. This is because these IP blocks can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * also appear in other SoCs, either from TI (such as DaVinci) or from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * other manufacturers; and drivers should be reusable across other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * platforms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * The OMAP hwmod code also will attempt to reset and idle all on-chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * devices upon boot. The goal here is for the kernel to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * completely self-reliant and independent from bootloaders. This is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * to ensure a repeatable configuration, both to ensure consistent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * runtime behavior, and to make it easier for others to reproduce
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * bugs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * OMAP module activity states
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * ---------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * The hwmod code considers modules to be in one of several activity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * states. IP blocks start out in an UNKNOWN state, then once they
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * are registered via the hwmod code, proceed to the REGISTERED state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * Once their clock names are resolved to clock pointers, the module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * enters the CLKS_INITED state; and finally, once the module has been
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * reset and the integration registers programmed, the INITIALIZED state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * is entered. The hwmod code will then place the module into either
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * the IDLE state to save power, or in the case of a critical system
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * module, the ENABLED state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * OMAP core integration code can then call omap_hwmod*() functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * directly to move the module between the IDLE, ENABLED, and DISABLED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * states, as needed. This is done during both the PM idle loop, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * in the OMAP core integration code's implementation of the PM runtime
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * References
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * ----------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * This is a partial list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * - OMAP4430 Multimedia Device Silicon Revision 1.0 (SWPU140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * - Open Core Protocol Specification 2.2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * To do:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * - handle IO mapping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * - bus throughput & module latency measurement code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * XXX add tests at the beginning of each function to ensure the hwmod is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * in the appropriate state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * XXX error return values should be checked to ensure that they are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * appropriate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) #undef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #include <linux/memblock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #include <linux/platform_data/ti-sysc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #include <dt-bindings/bus/ti-sysc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #include <asm/system_misc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #include "clock.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #include "omap_hwmod.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) #include "soc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) #include "clockdomain.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) #include "hdq1w.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) #include "mmc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) #include "powerdomain.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #include "cm2xxx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #include "cm3xxx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #include "cm33xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) #include "prm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) #include "prm3xxx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #include "prm44xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #include "prm33xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #include "prminst44xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #include "pm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) #include "wd_timer.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /* Name of the OMAP hwmod for the MPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) #define MPU_INITIATOR_NAME "mpu"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * Number of struct omap_hwmod_link records per struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * omap_hwmod_ocp_if record (master->slave and slave->master)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) #define LINKS_PER_OCP_IF 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * Address offset (in bytes) between the reset control and the reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * status registers: 4 bytes on OMAP4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) #define OMAP4_RST_CTRL_ST_OFFSET 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * Maximum length for module clock handle names
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) #define MOD_CLK_MAX_NAME_LEN 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * struct clkctrl_provider - clkctrl provider mapping data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * @num_addrs: number of base address ranges for the provider
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * @addr: base address(es) for the provider
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * @size: size(s) of the provider address space(s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * @node: device node associated with the provider
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * @link: list link
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) struct clkctrl_provider {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) int num_addrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) u32 *addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) u32 *size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct device_node *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct list_head link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static LIST_HEAD(clkctrl_providers);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * struct omap_hwmod_reset - IP specific reset functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * @match: string to match against the module name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * @len: number of characters to match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * @reset: IP specific reset function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * Used only in cases where struct omap_hwmod is dynamically allocated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct omap_hwmod_reset {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) const char *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) int (*reset)(struct omap_hwmod *oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * @enable_module: function to enable a module (via MODULEMODE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * @disable_module: function to disable a module (via MODULEMODE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * XXX Eventually this functionality will be hidden inside the PRM/CM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * device drivers. Until then, this should avoid huge blocks of cpu_is_*()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * conditionals in this code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) struct omap_hwmod_soc_ops {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) void (*enable_module)(struct omap_hwmod *oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) int (*disable_module)(struct omap_hwmod *oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) int (*wait_target_ready)(struct omap_hwmod *oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) int (*assert_hardreset)(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) struct omap_hwmod_rst_info *ohri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) int (*deassert_hardreset)(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) struct omap_hwmod_rst_info *ohri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) int (*is_hardreset_asserted)(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) struct omap_hwmod_rst_info *ohri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) int (*init_clkdm)(struct omap_hwmod *oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) void (*update_context_lost)(struct omap_hwmod *oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) int (*get_context_lost)(struct omap_hwmod *oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) int (*disable_direct_prcm)(struct omap_hwmod *oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) u32 (*xlate_clkctrl)(struct omap_hwmod *oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static struct omap_hwmod_soc_ops soc_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) /* omap_hwmod_list contains all registered struct omap_hwmods */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) static LIST_HEAD(omap_hwmod_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) static DEFINE_MUTEX(list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /* mpu_oh: used to add/remove MPU initiator from sleepdep list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) static struct omap_hwmod *mpu_oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) /* inited: set to true once the hwmod code is initialized */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) static bool inited;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) /* Private functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * Load the current value of the hwmod OCP_SYSCONFIG register into the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) * struct omap_hwmod for later use. Returns -EINVAL if the hwmod has no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * OCP_SYSCONFIG register or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int _update_sysc_cache(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (!oh->class->sysc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) WARN(1, "omap_hwmod: %s: cannot read OCP_SYSCONFIG: not defined on hwmod's class\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /* XXX ensure module interface clock is up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) oh->_sysc_cache = omap_hwmod_read(oh, oh->class->sysc->sysc_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (!(oh->class->sysc->sysc_flags & SYSC_NO_CACHE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) oh->_int_flags |= _HWMOD_SYSCONFIG_LOADED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * _write_sysconfig - write a value to the module's OCP_SYSCONFIG register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * @v: OCP_SYSCONFIG value to write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * Write @v into the module class' OCP_SYSCONFIG register, if it has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) * one. No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static void _write_sysconfig(u32 v, struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (!oh->class->sysc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) WARN(1, "omap_hwmod: %s: cannot write OCP_SYSCONFIG: not defined on hwmod's class\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* XXX ensure module interface clock is up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) /* Module might have lost context, always update cache and register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) oh->_sysc_cache = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * Some IP blocks (such as RTC) require unlocking of IP before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) * accessing its registers. If a function pointer is present
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * to unlock, then call it before accessing sysconfig and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * call lock after writing sysconfig.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (oh->class->unlock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) oh->class->unlock(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) omap_hwmod_write(v, oh, oh->class->sysc->sysc_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (oh->class->lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) oh->class->lock(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) * _set_master_standbymode: set the OCP_SYSCONFIG MIDLEMODE field in @v
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) * @standbymode: MIDLEMODE field bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) * @v: pointer to register contents to modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) * Update the master standby mode bits in @v to be @standbymode for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) * the @oh hwmod. Does not write to the hardware. Returns -EINVAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * upon error or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) u32 *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) u32 mstandby_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) u8 mstandby_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (!oh->class->sysc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) !(oh->class->sysc->sysc_flags & SYSC_HAS_MIDLEMODE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (!oh->class->sysc->sysc_fields) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) mstandby_shift = oh->class->sysc->sysc_fields->midle_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) mstandby_mask = (0x3 << mstandby_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) *v &= ~mstandby_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) *v |= __ffs(standbymode) << mstandby_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) * _set_slave_idlemode: set the OCP_SYSCONFIG SIDLEMODE field in @v
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) * @idlemode: SIDLEMODE field bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) * @v: pointer to register contents to modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) * Update the slave idle mode bits in @v to be @idlemode for the @oh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) * hwmod. Does not write to the hardware. Returns -EINVAL upon error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) * or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) u32 sidle_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) u8 sidle_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (!oh->class->sysc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) !(oh->class->sysc->sysc_flags & SYSC_HAS_SIDLEMODE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (!oh->class->sysc->sysc_fields) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) sidle_shift = oh->class->sysc->sysc_fields->sidle_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) sidle_mask = (0x3 << sidle_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) *v &= ~sidle_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) *v |= __ffs(idlemode) << sidle_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) * _set_clockactivity: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * @clockact: CLOCKACTIVITY field bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * @v: pointer to register contents to modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * Update the clockactivity mode bits in @v to be @clockact for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * @oh hwmod. Used for additional powersaving on some modules. Does
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * not write to the hardware. Returns -EINVAL upon error or 0 upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) u32 clkact_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) u8 clkact_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (!oh->class->sysc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) !(oh->class->sysc->sysc_flags & SYSC_HAS_CLOCKACTIVITY))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (!oh->class->sysc->sysc_fields) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) clkact_shift = oh->class->sysc->sysc_fields->clkact_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) clkact_mask = (0x3 << clkact_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) *v &= ~clkact_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) *v |= clockact << clkact_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) * _set_softreset: set OCP_SYSCONFIG.SOFTRESET bit in @v
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * @v: pointer to register contents to modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * Set the SOFTRESET bit in @v for hwmod @oh. Returns -EINVAL upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * error or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) static int _set_softreset(struct omap_hwmod *oh, u32 *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) u32 softrst_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) if (!oh->class->sysc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) if (!oh->class->sysc->sysc_fields) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) *v |= softrst_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * _clear_softreset: clear OCP_SYSCONFIG.SOFTRESET bit in @v
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * @v: pointer to register contents to modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) * Clear the SOFTRESET bit in @v for hwmod @oh. Returns -EINVAL upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) * error or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) static int _clear_softreset(struct omap_hwmod *oh, u32 *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) u32 softrst_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) if (!oh->class->sysc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (!oh->class->sysc->sysc_fields) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) WARN(1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) "omap_hwmod: %s: sysc_fields absent for sysconfig class\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) *v &= ~softrst_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) * _wait_softreset_complete - wait for an OCP softreset to complete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) * @oh: struct omap_hwmod * to wait on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) * Wait until the IP block represented by @oh reports that its OCP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) * softreset is complete. This can be triggered by software (see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) * _ocp_softreset()) or by hardware upon returning from off-mode (one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) * example is HSMMC). Waits for up to MAX_MODULE_SOFTRESET_WAIT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) * microseconds. Returns the number of microseconds waited.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) static int _wait_softreset_complete(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) struct omap_hwmod_class_sysconfig *sysc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) u32 softrst_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) int c = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) sysc = oh->class->sysc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (sysc->sysc_flags & SYSS_HAS_RESET_STATUS && sysc->syss_offs > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) omap_test_timeout((omap_hwmod_read(oh, sysc->syss_offs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) & SYSS_RESETDONE_MASK),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) MAX_MODULE_SOFTRESET_WAIT, c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) else if (sysc->sysc_flags & SYSC_HAS_RESET_STATUS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) softrst_mask = (0x1 << sysc->sysc_fields->srst_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) omap_test_timeout(!(omap_hwmod_read(oh, sysc->sysc_offs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) & softrst_mask),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) MAX_MODULE_SOFTRESET_WAIT, c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) return c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * _set_dmadisable: set OCP_SYSCONFIG.DMADISABLE bit in @v
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) * The DMADISABLE bit is a semi-automatic bit present in sysconfig register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) * of some modules. When the DMA must perform read/write accesses, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) * DMADISABLE bit is cleared by the hardware. But when the DMA must stop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) * for power management, software must set the DMADISABLE bit back to 1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) * Set the DMADISABLE bit in @v for hwmod @oh. Returns -EINVAL upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) * error or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) static int _set_dmadisable(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) u32 dmadisable_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (!oh->class->sysc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) !(oh->class->sysc->sysc_flags & SYSC_HAS_DMADISABLE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if (!oh->class->sysc->sysc_fields) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) /* clocks must be on for this operation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (oh->_state != _HWMOD_STATE_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) pr_warn("omap_hwmod: %s: dma can be disabled only from enabled state\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) pr_debug("omap_hwmod: %s: setting DMADISABLE\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) v = oh->_sysc_cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) dmadisable_mask =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) (0x1 << oh->class->sysc->sysc_fields->dmadisable_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) v |= dmadisable_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) _write_sysconfig(v, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * _set_module_autoidle: set the OCP_SYSCONFIG AUTOIDLE field in @v
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * @autoidle: desired AUTOIDLE bitfield value (0 or 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) * @v: pointer to register contents to modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * Update the module autoidle bit in @v to be @autoidle for the @oh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * hwmod. The autoidle bit controls whether the module can gate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * internal clocks automatically when it isn't doing anything; the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) * exact function of this bit varies on a per-module basis. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * function does not write to the hardware. Returns -EINVAL upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) * error or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) u32 *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) u32 autoidle_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) u8 autoidle_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (!oh->class->sysc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) !(oh->class->sysc->sysc_flags & SYSC_HAS_AUTOIDLE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (!oh->class->sysc->sysc_fields) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) autoidle_shift = oh->class->sysc->sysc_fields->autoidle_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) autoidle_mask = (0x1 << autoidle_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) *v &= ~autoidle_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) *v |= autoidle << autoidle_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) * Allow the hardware module @oh to send wakeups. Returns -EINVAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) * upon error or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (!oh->class->sysc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (!oh->class->sysc->sysc_fields) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) *v |= 0x1 << oh->class->sysc->sysc_fields->enwkup_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) /* XXX test pwrdm_get_wken for this hwmod's subsystem */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) static struct clockdomain *_get_clkdm(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) struct clk_hw_omap *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (oh->clkdm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) return oh->clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) } else if (oh->_clk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) if (!omap2_clk_is_hw_omap(__clk_get_hw(oh->_clk)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) clk = to_clk_hw_omap(__clk_get_hw(oh->_clk));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) return clk->clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) * _add_initiator_dep: prevent @oh from smart-idling while @init_oh is active
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) * Prevent the hardware module @oh from entering idle while the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) * hardare module initiator @init_oh is active. Useful when a module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) * will be accessed by a particular initiator (e.g., if a module will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) * be accessed by the IVA, there should be a sleepdep between the IVA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) * initiator and the module). Only applies to modules in smart-idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) * mode. If the clockdomain is marked as not needing autodeps, return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) * 0 without doing anything. Otherwise, returns -EINVAL upon error or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) * passes along clkdm_add_sleepdep() value upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) struct clockdomain *clkdm, *init_clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) clkdm = _get_clkdm(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) init_clkdm = _get_clkdm(init_oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) if (!clkdm || !init_clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) if (clkdm && clkdm->flags & CLKDM_NO_AUTODEPS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) return clkdm_add_sleepdep(clkdm, init_clkdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) * _del_initiator_dep: allow @oh to smart-idle even if @init_oh is active
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) * Allow the hardware module @oh to enter idle while the hardare
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) * module initiator @init_oh is active. Useful when a module will not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) * be accessed by a particular initiator (e.g., if a module will not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) * be accessed by the IVA, there should be no sleepdep between the IVA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) * initiator and the module). Only applies to modules in smart-idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) * mode. If the clockdomain is marked as not needing autodeps, return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) * 0 without doing anything. Returns -EINVAL upon error or passes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) * along clkdm_del_sleepdep() value upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) struct clockdomain *clkdm, *init_clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) clkdm = _get_clkdm(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) init_clkdm = _get_clkdm(init_oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) if (!clkdm || !init_clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) if (clkdm && clkdm->flags & CLKDM_NO_AUTODEPS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) return clkdm_del_sleepdep(clkdm, init_clkdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) static const struct of_device_id ti_clkctrl_match_table[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) { .compatible = "ti,clkctrl" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) static int __init _setup_clkctrl_provider(struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) const __be32 *addrp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) struct clkctrl_provider *provider;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) u64 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) provider = memblock_alloc(sizeof(*provider), SMP_CACHE_BYTES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (!provider)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) provider->node = np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) provider->num_addrs =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) of_property_count_elems_of_size(np, "reg", sizeof(u32)) / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) provider->addr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) memblock_alloc(sizeof(void *) * provider->num_addrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) SMP_CACHE_BYTES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (!provider->addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) provider->size =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) memblock_alloc(sizeof(u32) * provider->num_addrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) SMP_CACHE_BYTES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (!provider->size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) for (i = 0; i < provider->num_addrs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) addrp = of_get_address(np, i, &size, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) provider->addr[i] = (u32)of_translate_address(np, addrp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) provider->size[i] = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) pr_debug("%s: %pOF: %x...%x\n", __func__, np, provider->addr[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) provider->addr[i] + provider->size[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) list_add(&provider->link, &clkctrl_providers);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) static int __init _init_clkctrl_providers(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) for_each_matching_node(np, ti_clkctrl_match_table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) ret = _setup_clkctrl_provider(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) static u32 _omap4_xlate_clkctrl(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) if (!oh->prcm.omap4.modulemode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) return omap_cm_xlate_clkctrl(oh->clkdm->prcm_partition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) oh->clkdm->cm_inst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) oh->prcm.omap4.clkctrl_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) static struct clk *_lookup_clkctrl_clk(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) struct clkctrl_provider *provider;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) u32 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) if (!soc_ops.xlate_clkctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) addr = soc_ops.xlate_clkctrl(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) if (!addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) pr_debug("%s: %s: addr=%x\n", __func__, oh->name, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) list_for_each_entry(provider, &clkctrl_providers, link) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) for (i = 0; i < provider->num_addrs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) if (provider->addr[i] <= addr &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) provider->addr[i] + provider->size[i] > addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) struct of_phandle_args clkspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) clkspec.np = provider->node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) clkspec.args_count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) clkspec.args[0] = addr - provider->addr[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) clkspec.args[1] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) clk = of_clk_get_from_provider(&clkspec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) pr_debug("%s: %s got %p (offset=%x, provider=%pOF)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) __func__, oh->name, clk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) clkspec.args[0], provider->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) return clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) * _init_main_clk - get a struct clk * for the the hwmod's main functional clk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) * Called from _init_clocks(). Populates the @oh _clk (main
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) * functional clock pointer) if a clock matching the hwmod name is found,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) * or a main_clk is present. Returns 0 on success or -EINVAL on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) static int _init_main_clk(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) struct clk *clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) clk = _lookup_clkctrl_clk(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) if (!IS_ERR_OR_NULL(clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) pr_debug("%s: mapped main_clk %s for %s\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) __clk_get_name(clk), oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) oh->main_clk = __clk_get_name(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) oh->_clk = clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) soc_ops.disable_direct_prcm(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) if (!oh->main_clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) oh->_clk = clk_get(NULL, oh->main_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) if (IS_ERR(oh->_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) pr_warn("omap_hwmod: %s: cannot clk_get main_clk %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) oh->name, oh->main_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) * HACK: This needs a re-visit once clk_prepare() is implemented
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) * to do something meaningful. Today its just a no-op.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) * If clk_prepare() is used at some point to do things like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) * voltage scaling etc, then this would have to be moved to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) * some point where subsystems like i2c and pmic become
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) * available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) clk_prepare(oh->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) if (!_get_clkdm(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) pr_debug("omap_hwmod: %s: missing clockdomain for %s.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) oh->name, oh->main_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) * _init_interface_clks - get a struct clk * for the the hwmod's interface clks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) * Called from _init_clocks(). Populates the @oh OCP slave interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) * clock pointers. Returns 0 on success or -EINVAL on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) static int _init_interface_clks(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) struct omap_hwmod_ocp_if *os;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) struct clk *c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) list_for_each_entry(os, &oh->slave_ports, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) if (!os->clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) c = clk_get(NULL, os->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) if (IS_ERR(c)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) pr_warn("omap_hwmod: %s: cannot clk_get interface_clk %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) oh->name, os->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) os->_clk = c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) * HACK: This needs a re-visit once clk_prepare() is implemented
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) * to do something meaningful. Today its just a no-op.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) * If clk_prepare() is used at some point to do things like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) * voltage scaling etc, then this would have to be moved to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) * some point where subsystems like i2c and pmic become
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) * available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) clk_prepare(os->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) * _init_opt_clk - get a struct clk * for the the hwmod's optional clocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) * Called from _init_clocks(). Populates the @oh omap_hwmod_opt_clk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) * clock pointers. Returns 0 on success or -EINVAL on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) static int _init_opt_clks(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) struct omap_hwmod_opt_clk *oc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) struct clk *c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) c = clk_get(NULL, oc->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) if (IS_ERR(c)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) pr_warn("omap_hwmod: %s: cannot clk_get opt_clk %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) oh->name, oc->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) oc->_clk = c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) * HACK: This needs a re-visit once clk_prepare() is implemented
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) * to do something meaningful. Today its just a no-op.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) * If clk_prepare() is used at some point to do things like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) * voltage scaling etc, then this would have to be moved to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) * some point where subsystems like i2c and pmic become
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) * available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) clk_prepare(oc->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) static void _enable_optional_clocks(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) struct omap_hwmod_opt_clk *oc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) if (oc->_clk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) pr_debug("omap_hwmod: enable %s:%s\n", oc->role,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) __clk_get_name(oc->_clk));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) clk_enable(oc->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) static void _disable_optional_clocks(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) struct omap_hwmod_opt_clk *oc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) if (oc->_clk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) pr_debug("omap_hwmod: disable %s:%s\n", oc->role,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) __clk_get_name(oc->_clk));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) clk_disable(oc->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) * _enable_clocks - enable hwmod main clock and interface clocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) * Enables all clocks necessary for register reads and writes to succeed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) * on the hwmod @oh. Returns 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) static int _enable_clocks(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) struct omap_hwmod_ocp_if *os;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) _enable_optional_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) if (oh->_clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) clk_enable(oh->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) list_for_each_entry(os, &oh->slave_ports, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) omap2_clk_deny_idle(os->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) clk_enable(os->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) /* The opt clocks are controlled by the device driver. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) * _omap4_clkctrl_managed_by_clkfwk - true if clkctrl managed by clock framework
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) static bool _omap4_clkctrl_managed_by_clkfwk(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) if (oh->prcm.omap4.flags & HWMOD_OMAP4_CLKFWK_CLKCTR_CLOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) * _omap4_has_clkctrl_clock - returns true if a module has clkctrl clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) static bool _omap4_has_clkctrl_clock(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) if (oh->prcm.omap4.clkctrl_offs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) if (!oh->prcm.omap4.clkctrl_offs &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) oh->prcm.omap4.flags & HWMOD_OMAP4_ZERO_CLKCTRL_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) * _disable_clocks - disable hwmod main clock and interface clocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) * Disables the hwmod @oh main functional and interface clocks. Returns 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) static int _disable_clocks(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) struct omap_hwmod_ocp_if *os;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) if (oh->_clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) clk_disable(oh->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) list_for_each_entry(os, &oh->slave_ports, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) clk_disable(os->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) omap2_clk_allow_idle(os->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) _disable_optional_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) /* The opt clocks are controlled by the device driver. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) * _omap4_enable_module - enable CLKCTRL modulemode on OMAP4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) * Enables the PRCM module mode related to the hwmod @oh.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) * No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) static void _omap4_enable_module(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) if (!oh->clkdm || !oh->prcm.omap4.modulemode ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) _omap4_clkctrl_managed_by_clkfwk(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) pr_debug("omap_hwmod: %s: %s: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) oh->name, __func__, oh->prcm.omap4.modulemode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) omap_cm_module_enable(oh->prcm.omap4.modulemode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) oh->clkdm->prcm_partition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) oh->clkdm->cm_inst, oh->prcm.omap4.clkctrl_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) * _omap4_wait_target_disable - wait for a module to be disabled on OMAP4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) * Wait for a module @oh to enter slave idle. Returns 0 if the module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) * does not have an IDLEST bit or if the module successfully enters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) * slave idle; otherwise, pass along the return value of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) * appropriate *_cm*_wait_module_idle() function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) static int _omap4_wait_target_disable(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) if (oh->_int_flags & _HWMOD_NO_MPU_PORT || !oh->clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) if (oh->flags & HWMOD_NO_IDLEST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) if (_omap4_clkctrl_managed_by_clkfwk(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) if (!_omap4_has_clkctrl_clock(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) return omap_cm_wait_module_idle(oh->clkdm->prcm_partition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) oh->clkdm->cm_inst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) oh->prcm.omap4.clkctrl_offs, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) * _save_mpu_port_index - find and save the index to @oh's MPU port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) * Determines the array index of the OCP slave port that the MPU uses
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) * to address the device, and saves it into the struct omap_hwmod.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) * Intended to be called during hwmod registration only. No return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) * value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) static void __init _save_mpu_port_index(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) struct omap_hwmod_ocp_if *os = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) oh->_int_flags |= _HWMOD_NO_MPU_PORT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) list_for_each_entry(os, &oh->slave_ports, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) if (os->user & OCP_USER_MPU) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) oh->_mpu_port = os;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) oh->_int_flags &= ~_HWMOD_NO_MPU_PORT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) * _find_mpu_rt_port - return omap_hwmod_ocp_if accessible by the MPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) * Given a pointer to a struct omap_hwmod record @oh, return a pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) * to the struct omap_hwmod_ocp_if record that is used by the MPU to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) * communicate with the IP block. This interface need not be directly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) * connected to the MPU (and almost certainly is not), but is directly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) * connected to the IP block represented by @oh. Returns a pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) * to the struct omap_hwmod_ocp_if * upon success, or returns NULL upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) * error or if there does not appear to be a path from the MPU to this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) * IP block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) static struct omap_hwmod_ocp_if *_find_mpu_rt_port(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) if (!oh || oh->_int_flags & _HWMOD_NO_MPU_PORT || oh->slaves_cnt == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) return oh->_mpu_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) * _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) * Ensure that the OCP_SYSCONFIG register for the IP block represented
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) * by @oh is set to indicate to the PRCM that the IP block is active.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) * Usually this means placing the module into smart-idle mode and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) * smart-standby, but if there is a bug in the automatic idle handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) * for the IP block, it may need to be placed into the force-idle or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) * no-idle variants of these modes. No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) static void _enable_sysc(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) u8 idlemode, sf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) bool clkdm_act;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) struct clockdomain *clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) if (!oh->class->sysc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) * Wait until reset has completed, this is needed as the IP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) * block is reset automatically by hardware in some cases
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) * (off-mode for example), and the drivers require the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) * IP to be ready when they access it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) _enable_optional_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) _wait_softreset_complete(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) _disable_optional_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) v = oh->_sysc_cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) sf = oh->class->sysc->sysc_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) clkdm = _get_clkdm(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) if (sf & SYSC_HAS_SIDLEMODE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) if (oh->flags & HWMOD_SWSUP_SIDLE ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) oh->flags & HWMOD_SWSUP_SIDLE_ACT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) idlemode = HWMOD_IDLEMODE_NO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) if (sf & SYSC_HAS_ENAWAKEUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) _enable_wakeup(oh, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) idlemode = HWMOD_IDLEMODE_SMART_WKUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) idlemode = HWMOD_IDLEMODE_SMART;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) * This is special handling for some IPs like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) * 32k sync timer. Force them to idle!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) clkdm_act = (clkdm && clkdm->flags & CLKDM_ACTIVE_WITH_MPU);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) if (clkdm_act && !(oh->class->sysc->idlemodes &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) (SIDLE_SMART | SIDLE_SMART_WKUP)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) idlemode = HWMOD_IDLEMODE_FORCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) _set_slave_idlemode(oh, idlemode, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) if (sf & SYSC_HAS_MIDLEMODE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) if (oh->flags & HWMOD_FORCE_MSTANDBY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) idlemode = HWMOD_IDLEMODE_FORCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) } else if (oh->flags & HWMOD_SWSUP_MSTANDBY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) idlemode = HWMOD_IDLEMODE_NO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) if (sf & SYSC_HAS_ENAWAKEUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) _enable_wakeup(oh, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) idlemode = HWMOD_IDLEMODE_SMART_WKUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) idlemode = HWMOD_IDLEMODE_SMART;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) _set_master_standbymode(oh, idlemode, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) * XXX The clock framework should handle this, by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) * calling into this code. But this must wait until the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) * clock structures are tagged with omap_hwmod entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) if ((oh->flags & HWMOD_SET_DEFAULT_CLOCKACT) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) (sf & SYSC_HAS_CLOCKACTIVITY))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) _set_clockactivity(oh, CLOCKACT_TEST_ICLK, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) _write_sysconfig(v, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) * Set the autoidle bit only after setting the smartidle bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) * Setting this will not have any impact on the other modules.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) if (sf & SYSC_HAS_AUTOIDLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) 0 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) _set_module_autoidle(oh, idlemode, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) _write_sysconfig(v, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) * _idle_sysc - try to put a module into idle via OCP_SYSCONFIG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) * If module is marked as SWSUP_SIDLE, force the module into slave
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) * idle; otherwise, configure it for smart-idle. If module is marked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) * as SWSUP_MSUSPEND, force the module into master standby; otherwise,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) * configure it for smart-standby. No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) static void _idle_sysc(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) u8 idlemode, sf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) if (!oh->class->sysc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) v = oh->_sysc_cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) sf = oh->class->sysc->sysc_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) if (sf & SYSC_HAS_SIDLEMODE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) if (oh->flags & HWMOD_SWSUP_SIDLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) idlemode = HWMOD_IDLEMODE_FORCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) if (sf & SYSC_HAS_ENAWAKEUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) _enable_wakeup(oh, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) idlemode = HWMOD_IDLEMODE_SMART_WKUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) idlemode = HWMOD_IDLEMODE_SMART;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) _set_slave_idlemode(oh, idlemode, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) if (sf & SYSC_HAS_MIDLEMODE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) if ((oh->flags & HWMOD_SWSUP_MSTANDBY) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) (oh->flags & HWMOD_FORCE_MSTANDBY)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) idlemode = HWMOD_IDLEMODE_FORCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) if (sf & SYSC_HAS_ENAWAKEUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) _enable_wakeup(oh, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) idlemode = HWMOD_IDLEMODE_SMART_WKUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) idlemode = HWMOD_IDLEMODE_SMART;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) _set_master_standbymode(oh, idlemode, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) /* If the cached value is the same as the new value, skip the write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) if (oh->_sysc_cache != v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) _write_sysconfig(v, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) * _shutdown_sysc - force a module into idle via OCP_SYSCONFIG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) * Force the module into slave idle and master suspend. No return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) * value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) static void _shutdown_sysc(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) u8 sf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) if (!oh->class->sysc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) v = oh->_sysc_cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) sf = oh->class->sysc->sysc_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) if (sf & SYSC_HAS_SIDLEMODE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) _set_slave_idlemode(oh, HWMOD_IDLEMODE_FORCE, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) if (sf & SYSC_HAS_MIDLEMODE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) _set_master_standbymode(oh, HWMOD_IDLEMODE_FORCE, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) if (sf & SYSC_HAS_AUTOIDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) _set_module_autoidle(oh, 1, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) _write_sysconfig(v, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) * _lookup - find an omap_hwmod by name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) * @name: find an omap_hwmod by name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) * Return a pointer to an omap_hwmod by name, or NULL if not found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) static struct omap_hwmod *_lookup(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) struct omap_hwmod *oh, *temp_oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) oh = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) list_for_each_entry(temp_oh, &omap_hwmod_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) if (!strcmp(name, temp_oh->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) oh = temp_oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) return oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) * _init_clkdm - look up a clockdomain name, store pointer in omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) * Convert a clockdomain name stored in a struct omap_hwmod into a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) * clockdomain pointer, and save it into the struct omap_hwmod.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) * Return -EINVAL if the clkdm_name lookup failed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) static int _init_clkdm(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) if (!oh->clkdm_name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) pr_debug("omap_hwmod: %s: missing clockdomain\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) oh->clkdm = clkdm_lookup(oh->clkdm_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) if (!oh->clkdm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) pr_warn("omap_hwmod: %s: could not associate to clkdm %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) oh->name, oh->clkdm_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) pr_debug("omap_hwmod: %s: associated to clkdm %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) oh->name, oh->clkdm_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) * _init_clocks - clk_get() all clocks associated with this hwmod. Retrieve as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) * well the clockdomain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) * @np: device_node mapped to this hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) * Called by omap_hwmod_setup_*() (after omap2_clk_init()).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) * Resolves all clock names embedded in the hwmod. Returns 0 on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) * success, or a negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) static int _init_clocks(struct omap_hwmod *oh, struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) if (oh->_state != _HWMOD_STATE_REGISTERED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) if (soc_ops.init_clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) ret |= soc_ops.init_clkdm(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) ret |= _init_main_clk(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) ret |= _init_interface_clks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) ret |= _init_opt_clks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) oh->_state = _HWMOD_STATE_CLKS_INITED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) pr_warn("omap_hwmod: %s: cannot _init_clocks\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) * _lookup_hardreset - fill register bit info for this hwmod/reset line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) * @name: name of the reset line in the context of this hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) * @ohri: struct omap_hwmod_rst_info * that this function will fill in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) * Return the bit position of the reset line that match the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) * input name. Return -ENOENT if not found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) static int _lookup_hardreset(struct omap_hwmod *oh, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) struct omap_hwmod_rst_info *ohri)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) for (i = 0; i < oh->rst_lines_cnt; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) const char *rst_line = oh->rst_lines[i].name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) if (!strcmp(rst_line, name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) ohri->rst_shift = oh->rst_lines[i].rst_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) ohri->st_shift = oh->rst_lines[i].st_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) pr_debug("omap_hwmod: %s: %s: %s: rst %d st %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) oh->name, __func__, rst_line, ohri->rst_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) ohri->st_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) * _assert_hardreset - assert the HW reset line of submodules
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) * contained in the hwmod module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) * @name: name of the reset line to lookup and assert
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) * Some IP like dsp, ipu or iva contain processor that require an HW
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) * reset line to be assert / deassert in order to enable fully the IP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) * Returns -EINVAL if @oh is null, -ENOSYS if we have no way of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) * asserting the hardreset line on the currently-booted SoC, or passes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) * along the return value from _lookup_hardreset() or the SoC's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) * assert_hardreset code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) struct omap_hwmod_rst_info ohri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) if (!soc_ops.assert_hardreset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) return -ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) ret = _lookup_hardreset(oh, name, &ohri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) ret = soc_ops.assert_hardreset(oh, &ohri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) * _deassert_hardreset - deassert the HW reset line of submodules contained
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) * in the hwmod module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) * @name: name of the reset line to look up and deassert
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) * Some IP like dsp, ipu or iva contain processor that require an HW
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) * reset line to be assert / deassert in order to enable fully the IP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) * Returns -EINVAL if @oh is null, -ENOSYS if we have no way of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) * deasserting the hardreset line on the currently-booted SoC, or passes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) * along the return value from _lookup_hardreset() or the SoC's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) * deassert_hardreset code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) struct omap_hwmod_rst_info ohri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) if (!soc_ops.deassert_hardreset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) return -ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) ret = _lookup_hardreset(oh, name, &ohri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) if (oh->clkdm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) * A clockdomain must be in SW_SUP otherwise reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) * might not be completed. The clockdomain can be set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) * in HW_AUTO only when the module become ready.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) clkdm_deny_idle(oh->clkdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) ret = clkdm_hwmod_enable(oh->clkdm, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) oh->name, oh->clkdm->name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) _enable_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) if (soc_ops.enable_module)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) soc_ops.enable_module(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) ret = soc_ops.deassert_hardreset(oh, &ohri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) if (soc_ops.disable_module)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) soc_ops.disable_module(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) _disable_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) if (ret == -EBUSY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) pr_warn("omap_hwmod: %s: failed to hardreset\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) if (oh->clkdm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) * Set the clockdomain to HW_AUTO, assuming that the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) * previous state was HW_AUTO.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) clkdm_allow_idle(oh->clkdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) clkdm_hwmod_disable(oh->clkdm, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) * _read_hardreset - read the HW reset line state of submodules
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) * contained in the hwmod module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) * @name: name of the reset line to look up and read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) * Return the state of the reset line. Returns -EINVAL if @oh is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) * null, -ENOSYS if we have no way of reading the hardreset line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) * status on the currently-booted SoC, or passes along the return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) * value from _lookup_hardreset() or the SoC's is_hardreset_asserted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) * code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) static int _read_hardreset(struct omap_hwmod *oh, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) struct omap_hwmod_rst_info ohri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) if (!soc_ops.is_hardreset_asserted)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) return -ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) ret = _lookup_hardreset(oh, name, &ohri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) return soc_ops.is_hardreset_asserted(oh, &ohri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) * _are_all_hardreset_lines_asserted - return true if the @oh is hard-reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) * If all hardreset lines associated with @oh are asserted, then return true.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) * Otherwise, if part of @oh is out hardreset or if no hardreset lines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) * associated with @oh are asserted, then return false.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) * This function is used to avoid executing some parts of the IP block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) * enable/disable sequence if its hardreset line is set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) static bool _are_all_hardreset_lines_asserted(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) int i, rst_cnt = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) if (oh->rst_lines_cnt == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) for (i = 0; i < oh->rst_lines_cnt; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) rst_cnt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) if (oh->rst_lines_cnt == rst_cnt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) * _are_any_hardreset_lines_asserted - return true if any part of @oh is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) * hard-reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) * If any hardreset lines associated with @oh are asserted, then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) * return true. Otherwise, if no hardreset lines associated with @oh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) * are asserted, or if @oh has no hardreset lines, then return false.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) * This function is used to avoid executing some parts of the IP block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) * enable/disable sequence if any hardreset line is set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) int rst_cnt = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) for (i = 0; i < oh->rst_lines_cnt && rst_cnt == 0; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) rst_cnt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) return (rst_cnt) ? true : false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) * Disable the PRCM module mode related to the hwmod @oh.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) * Return EINVAL if the modulemode is not supported and 0 in case of success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) static int _omap4_disable_module(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) int v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) if (!oh->clkdm || !oh->prcm.omap4.modulemode ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) _omap4_clkctrl_managed_by_clkfwk(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) * Since integration code might still be doing something, only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) * disable if all lines are under hardreset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) if (_are_any_hardreset_lines_asserted(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) omap_cm_module_disable(oh->clkdm->prcm_partition, oh->clkdm->cm_inst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) oh->prcm.omap4.clkctrl_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) v = _omap4_wait_target_disable(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) if (v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) * enabled for this to work. Returns -ENOENT if the hwmod cannot be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) * reset this way, -EINVAL if the hwmod is in the wrong state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) * -ETIMEDOUT if the module did not reset in time, or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) * In OMAP3 a specific SYSSTATUS register is used to get the reset status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) * use the SYSCONFIG softreset bit to provide the status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) * Note that some IP like McBSP do have reset control but don't have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) * reset status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) static int _ocp_softreset(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) int c = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) if (!oh->class->sysc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) /* clocks must be on for this operation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) if (oh->_state != _HWMOD_STATE_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) pr_warn("omap_hwmod: %s: reset can only be entered from enabled state\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) /* For some modules, all optionnal clocks need to be enabled as well */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) _enable_optional_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) pr_debug("omap_hwmod: %s: resetting via OCP SOFTRESET\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) v = oh->_sysc_cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) ret = _set_softreset(oh, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) goto dis_opt_clks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) _write_sysconfig(v, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) if (oh->class->sysc->srst_udelay)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) udelay(oh->class->sysc->srst_udelay);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) c = _wait_softreset_complete(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) if (c == MAX_MODULE_SOFTRESET_WAIT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) pr_warn("omap_hwmod: %s: softreset failed (waited %d usec)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) oh->name, MAX_MODULE_SOFTRESET_WAIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) ret = -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) goto dis_opt_clks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) ret = _clear_softreset(oh, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) goto dis_opt_clks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) _write_sysconfig(v, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) * _wait_target_ready() or _reset()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) dis_opt_clks:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) _disable_optional_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) * _reset - reset an omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) * Resets an omap_hwmod @oh. If the module has a custom reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) * function pointer defined, then call it to reset the IP block, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) * pass along its return value to the caller. Otherwise, if the IP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) * block has an OCP_SYSCONFIG register with a SOFTRESET bitfield
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) * associated with it, call a function to reset the IP block via that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) * method, and pass along the return value to the caller. Finally, if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) * the IP block has some hardreset lines associated with it, assert
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) * all of those, but do _not_ deassert them. (This is because driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) * authors have expressed an apparent requirement to control the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) * deassertion of the hardreset lines themselves.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) * The default software reset mechanism for most OMAP IP blocks is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) * triggered via the OCP_SYSCONFIG.SOFTRESET bit. However, some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) * hwmods cannot be reset via this method. Some are not targets and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) * therefore have no OCP header registers to access. Others (like the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) * IVA) have idiosyncratic reset sequences. So for these relatively
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) * rare cases, custom reset code can be supplied in the struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) * omap_hwmod_class .reset function pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) * _set_dmadisable() is called to set the DMADISABLE bit so that it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) * does not prevent idling of the system. This is necessary for cases
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) * where ROMCODE/BOOTLOADER uses dma and transfers control to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) * kernel without disabling dma.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) * Passes along the return value from either _ocp_softreset() or the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) * custom reset function - these must return -EINVAL if the hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) * cannot be reset this way or if the hwmod is in the wrong state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) * -ETIMEDOUT if the module did not reset in time, or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) static int _reset(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) int i, r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) pr_debug("omap_hwmod: %s: resetting\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) if (oh->class->reset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) r = oh->class->reset(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) if (oh->rst_lines_cnt > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) for (i = 0; i < oh->rst_lines_cnt; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) _assert_hardreset(oh, oh->rst_lines[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) r = _ocp_softreset(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) if (r == -ENOENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) _set_dmadisable(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) * OCP_SYSCONFIG bits need to be reprogrammed after a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) * softreset. The _enable() function should be split to avoid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) * the rewrite of the OCP_SYSCONFIG register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) if (oh->class->sysc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) _update_sysc_cache(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) _enable_sysc(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) * _omap4_update_context_lost - increment hwmod context loss counter if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) * hwmod context was lost, and clear hardware context loss reg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) * @oh: hwmod to check for context loss
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) * If the PRCM indicates that the hwmod @oh lost context, increment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) * our in-memory context loss counter, and clear the RM_*_CONTEXT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) * bits. No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) static void _omap4_update_context_lost(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832) if (oh->prcm.omap4.flags & HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) if (!prm_was_any_context_lost_old(oh->clkdm->pwrdm.ptr->prcm_partition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) oh->clkdm->pwrdm.ptr->prcm_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) oh->prcm.omap4.context_offs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840) oh->prcm.omap4.context_lost_counter++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) prm_clear_context_loss_flags_old(oh->clkdm->pwrdm.ptr->prcm_partition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) oh->clkdm->pwrdm.ptr->prcm_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) oh->prcm.omap4.context_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) * _omap4_get_context_lost - get context loss counter for a hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) * @oh: hwmod to get context loss counter for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) * Returns the in-memory context loss counter for a hwmod.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) static int _omap4_get_context_lost(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) return oh->prcm.omap4.context_lost_counter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) * _enable - enable an omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) * Enables an omap_hwmod @oh such that the MPU can access the hwmod's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) * register target. Returns -EINVAL if the hwmod is in the wrong
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) * state or passes along the return value of _wait_target_ready().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) static int _enable(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) pr_debug("omap_hwmod: %s: enabling\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) * hwmods with HWMOD_INIT_NO_IDLE flag set are left in enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) * state at init.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) if (oh->_int_flags & _HWMOD_SKIP_ENABLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) oh->_int_flags &= ~_HWMOD_SKIP_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) if (oh->_state != _HWMOD_STATE_INITIALIZED &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) oh->_state != _HWMOD_STATE_IDLE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) oh->_state != _HWMOD_STATE_DISABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) WARN(1, "omap_hwmod: %s: enabled state can only be entered from initialized, idle, or disabled state\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) * If an IP block contains HW reset lines and all of them are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) * asserted, we let integration code associated with that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) * block handle the enable. We've received very little
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) * information on what those driver authors need, and until
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) * detailed information is provided and the driver code is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) * posted to the public lists, this is probably the best we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) * can do.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) if (_are_all_hardreset_lines_asserted(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) _add_initiator_dep(oh, mpu_oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) if (oh->clkdm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) * A clockdomain must be in SW_SUP before enabling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) * completely the module. The clockdomain can be set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) * in HW_AUTO only when the module become ready.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) clkdm_deny_idle(oh->clkdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) r = clkdm_hwmod_enable(oh->clkdm, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910) if (r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) oh->name, oh->clkdm->name, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917) _enable_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) if (soc_ops.enable_module)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) soc_ops.enable_module(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920) if (oh->flags & HWMOD_BLOCK_WFI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) cpu_idle_poll_ctrl(true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) if (soc_ops.update_context_lost)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924) soc_ops.update_context_lost(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) r = (soc_ops.wait_target_ready) ? soc_ops.wait_target_ready(oh) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) if (oh->clkdm && !(oh->flags & HWMOD_CLKDM_NOAUTO))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929) clkdm_allow_idle(oh->clkdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) if (!r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932) oh->_state = _HWMOD_STATE_ENABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) /* Access the sysconfig only if the target is ready */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) if (oh->class->sysc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) _update_sysc_cache(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) _enable_sysc(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) if (soc_ops.disable_module)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) soc_ops.disable_module(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) _disable_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) pr_err("omap_hwmod: %s: _wait_target_ready failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) oh->name, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947) if (oh->clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) clkdm_hwmod_disable(oh->clkdm, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) * _idle - idle an omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) * Idles an omap_hwmod @oh. This should be called once the hwmod has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959) * no further work. Returns -EINVAL if the hwmod is in the wrong
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) * state or returns 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) static int _idle(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) if (oh->flags & HWMOD_NO_IDLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965) oh->_int_flags |= _HWMOD_SKIP_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) pr_debug("omap_hwmod: %s: idling\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) if (_are_all_hardreset_lines_asserted(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974) if (oh->_state != _HWMOD_STATE_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) WARN(1, "omap_hwmod: %s: idle state can only be entered from enabled state\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) if (oh->class->sysc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) _idle_sysc(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) _del_initiator_dep(oh, mpu_oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985) * If HWMOD_CLKDM_NOAUTO is set then we don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) * deny idle the clkdm again since idle was already denied
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) * in _enable()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989) if (oh->clkdm && !(oh->flags & HWMOD_CLKDM_NOAUTO))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) clkdm_deny_idle(oh->clkdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) if (oh->flags & HWMOD_BLOCK_WFI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) cpu_idle_poll_ctrl(false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) if (soc_ops.disable_module)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) soc_ops.disable_module(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) * The module must be in idle mode before disabling any parents
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999) * clocks. Otherwise, the parent clock might be disabled before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) * the module transition is done, and thus will prevent the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001) * transition to complete properly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003) _disable_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004) if (oh->clkdm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) clkdm_allow_idle(oh->clkdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006) clkdm_hwmod_disable(oh->clkdm, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009) oh->_state = _HWMOD_STATE_IDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015) * _shutdown - shutdown an omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) * Shut down an omap_hwmod @oh. This should be called when the driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019) * used for the hwmod is removed or unloaded or if the driver is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020) * used by the system. Returns -EINVAL if the hwmod is in the wrong
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021) * state or returns 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023) static int _shutdown(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026) u8 prev_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028) if (_are_all_hardreset_lines_asserted(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031) if (oh->_state != _HWMOD_STATE_IDLE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032) oh->_state != _HWMOD_STATE_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) WARN(1, "omap_hwmod: %s: disabled state can only be entered from idle, or enabled state\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034) oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038) pr_debug("omap_hwmod: %s: disabling\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040) if (oh->class->pre_shutdown) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041) prev_state = oh->_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042) if (oh->_state == _HWMOD_STATE_IDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043) _enable(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044) ret = oh->class->pre_shutdown(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046) if (prev_state == _HWMOD_STATE_IDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047) _idle(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052) if (oh->class->sysc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053) if (oh->_state == _HWMOD_STATE_IDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054) _enable(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055) _shutdown_sysc(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058) /* clocks and deps are already disabled in idle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059) if (oh->_state == _HWMOD_STATE_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060) _del_initiator_dep(oh, mpu_oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061) /* XXX what about the other system initiators here? dma, dsp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062) if (oh->flags & HWMOD_BLOCK_WFI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063) cpu_idle_poll_ctrl(false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064) if (soc_ops.disable_module)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065) soc_ops.disable_module(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066) _disable_clocks(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067) if (oh->clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068) clkdm_hwmod_disable(oh->clkdm, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070) /* XXX Should this code also force-disable the optional clocks? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072) for (i = 0; i < oh->rst_lines_cnt; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073) _assert_hardreset(oh, oh->rst_lines[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2075) oh->_state = _HWMOD_STATE_DISABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2076)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2077) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2078) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2080) static int of_dev_find_hwmod(struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2081) struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2082) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2083) int count, i, res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2084) const char *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2085)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2086) count = of_property_count_strings(np, "ti,hwmods");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2087) if (count < 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2088) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2089)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2090) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2091) res = of_property_read_string_index(np, "ti,hwmods",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2092) i, &p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2093) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2094) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2095) if (!strcmp(p, oh->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2096) pr_debug("omap_hwmod: dt %pOFn[%i] uses hwmod %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2097) np, i, oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2098) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2099) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2102) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2105) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2106) * of_dev_hwmod_lookup - look up needed hwmod from dt blob
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2107) * @np: struct device_node *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2108) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2109) * @index: index of the entry found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2110) * @found: struct device_node * found or NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2111) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2112) * Parse the dt blob and find out needed hwmod. Recursive function is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2113) * implemented to take care hierarchical dt blob parsing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2114) * Return: Returns 0 on success, -ENODEV when not found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2115) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2116) static int of_dev_hwmod_lookup(struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2117) struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2118) int *index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2119) struct device_node **found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2121) struct device_node *np0 = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2122) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2124) res = of_dev_find_hwmod(np, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2125) if (res >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2126) *found = np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2127) *index = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2128) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2131) for_each_child_of_node(np, np0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2132) struct device_node *fc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2133) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2135) res = of_dev_hwmod_lookup(np0, oh, &i, &fc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2136) if (res == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2137) *found = fc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2138) *index = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2139) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2143) *found = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2144) *index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2146) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2149) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2150) * omap_hwmod_fix_mpu_rt_idx - fix up mpu_rt_idx register offsets
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2151) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2152) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2153) * @np: struct device_node *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2154) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2155) * Fix up module register offsets for modules with mpu_rt_idx.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2156) * Only needed for cpsw with interconnect target module defined
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2157) * in device tree while still using legacy hwmod platform data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2158) * for rev, sysc and syss registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2159) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2160) * Can be removed when all cpsw hwmod platform data has been
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2161) * dropped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2162) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2163) static void omap_hwmod_fix_mpu_rt_idx(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2164) struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2165) struct resource *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2167) struct device_node *child = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2168) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2170) child = of_get_next_child(np, child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2171) if (!child)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2172) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2174) error = of_address_to_resource(child, oh->mpu_rt_idx, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2175) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2176) pr_err("%s: error mapping mpu_rt_idx: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2177) __func__, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2180) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2181) * omap_hwmod_parse_module_range - map module IO range from device tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2182) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2183) * @np: struct device_node *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2184) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2185) * Parse the device tree range an interconnect target module provides
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2186) * for it's child device IP blocks. This way we can support the old
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2187) * "ti,hwmods" property with just dts data without a need for platform
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2188) * data for IO resources. And we don't need all the child IP device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2189) * nodes available in the dts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2190) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2191) int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2192) struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2193) struct resource *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2195) struct property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2196) const __be32 *ranges;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2197) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2198) u32 nr_addr, nr_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2199) u64 base, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2200) int len, error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2202) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2203) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2205) ranges = of_get_property(np, "ranges", &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2206) if (!ranges)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2207) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2209) len /= sizeof(*ranges);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2211) if (len < 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2212) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2214) of_property_for_each_string(np, "compatible", prop, name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2215) if (!strncmp("ti,sysc-", name, 8))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2216) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2218) if (!name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2219) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2221) error = of_property_read_u32(np, "#address-cells", &nr_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2222) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2223) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2225) error = of_property_read_u32(np, "#size-cells", &nr_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2226) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2227) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2229) if (nr_addr != 1 || nr_size != 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2230) pr_err("%s: invalid range for %s->%pOFn\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2231) oh->name, np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2232) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2235) ranges++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2236) base = of_translate_address(np, ranges++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2237) size = be32_to_cpup(ranges);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2239) pr_debug("omap_hwmod: %s %pOFn at 0x%llx size 0x%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2240) oh->name, np, base, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2242) if (oh && oh->mpu_rt_idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2243) omap_hwmod_fix_mpu_rt_idx(oh, np, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2245) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2248) res->start = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2249) res->end = base + size - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2250) res->flags = IORESOURCE_MEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2252) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2255) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2256) * _init_mpu_rt_base - populate the virtual address for a hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2257) * @oh: struct omap_hwmod * to locate the virtual address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2258) * @data: (unused, caller should pass NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2259) * @index: index of the reg entry iospace in device tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2260) * @np: struct device_node * of the IP block's device node in the DT data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2261) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2262) * Cache the virtual address used by the MPU to access this IP block's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2263) * registers. This address is needed early so the OCP registers that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2264) * are part of the device's address space can be ioremapped properly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2265) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2266) * If SYSC access is not needed, the registers will not be remapped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2267) * and non-availability of MPU access is not treated as an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2268) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2269) * Returns 0 on success, -EINVAL if an invalid hwmod is passed, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2270) * -ENXIO on absent or invalid register target address space.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2271) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2272) static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2273) int index, struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2275) void __iomem *va_start = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2276) struct resource res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2277) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2279) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2280) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2282) _save_mpu_port_index(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2284) /* if we don't need sysc access we don't need to ioremap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2285) if (!oh->class->sysc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2286) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2288) /* we can't continue without MPU PORT if we need sysc access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2289) if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2290) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2292) if (!np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2293) pr_err("omap_hwmod: %s: no dt node\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2294) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2297) /* Do we have a dts range for the interconnect target module? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2298) error = omap_hwmod_parse_module_range(oh, np, &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2299) if (!error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2300) va_start = ioremap(res.start, resource_size(&res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2302) /* No ranges, rely on device reg entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2303) if (!va_start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2304) va_start = of_iomap(np, index + oh->mpu_rt_idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2305) if (!va_start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2306) pr_err("omap_hwmod: %s: Missing dt reg%i for %pOF\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2307) oh->name, index, np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2308) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2311) pr_debug("omap_hwmod: %s: MPU register target at va %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2312) oh->name, va_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2314) oh->_mpu_rt_va = va_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2315) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2318) static void __init parse_module_flags(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2319) struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2320) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2321) if (of_find_property(np, "ti,no-reset-on-init", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2322) oh->flags |= HWMOD_INIT_NO_RESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2323) if (of_find_property(np, "ti,no-idle-on-init", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2324) oh->flags |= HWMOD_INIT_NO_IDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2325) if (of_find_property(np, "ti,no-idle", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2326) oh->flags |= HWMOD_NO_IDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2329) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2330) * _init - initialize internal data for the hwmod @oh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2331) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2332) * @n: (unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2333) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2334) * Look up the clocks and the address space used by the MPU to access
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2335) * registers belonging to the hwmod @oh. @oh must already be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2336) * registered at this point. This is the first of two phases for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2337) * hwmod initialization. Code called here does not touch any hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2338) * registers, it simply prepares internal data structures. Returns 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2339) * upon success or if the hwmod isn't registered or if the hwmod's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2340) * address space is not defined, or -EINVAL upon failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2341) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2342) static int __init _init(struct omap_hwmod *oh, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2343) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2344) int r, index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2345) struct device_node *np = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2346) struct device_node *bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2348) if (oh->_state != _HWMOD_STATE_REGISTERED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2349) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2351) bus = of_find_node_by_name(NULL, "ocp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2352) if (!bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2353) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2355) r = of_dev_hwmod_lookup(bus, oh, &index, &np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2356) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2357) pr_debug("omap_hwmod: %s missing dt data\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2358) else if (np && index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2359) pr_warn("omap_hwmod: %s using broken dt data from %pOFn\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2360) oh->name, np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2362) r = _init_mpu_rt_base(oh, NULL, index, np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2363) if (r < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2364) WARN(1, "omap_hwmod: %s: doesn't have mpu register target base\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2365) oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2366) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2369) r = _init_clocks(oh, np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2370) if (r < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2371) WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2372) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2375) if (np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2376) struct device_node *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2378) parse_module_flags(oh, np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2379) child = of_get_next_child(np, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2380) if (child)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2381) parse_module_flags(oh, child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2384) oh->_state = _HWMOD_STATE_INITIALIZED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2386) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2389) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2390) * _setup_iclk_autoidle - configure an IP block's interface clocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2391) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2392) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2393) * Set up the module's interface clocks. XXX This function is still mostly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2394) * a stub; implementing this properly requires iclk autoidle usecounting in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2395) * the clock code. No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2396) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2397) static void _setup_iclk_autoidle(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2399) struct omap_hwmod_ocp_if *os;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2401) if (oh->_state != _HWMOD_STATE_INITIALIZED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2402) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2404) list_for_each_entry(os, &oh->slave_ports, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2405) if (!os->_clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2406) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2408) if (os->flags & OCPIF_SWSUP_IDLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2409) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2410) * we might have multiple users of one iclk with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2411) * different requirements, disable autoidle when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2412) * the module is enabled, e.g. dss iclk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2413) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2414) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2415) /* we are enabling autoidle afterwards anyways */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2416) clk_enable(os->_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2420) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2423) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2424) * _setup_reset - reset an IP block during the setup process
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2425) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2426) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2427) * Reset the IP block corresponding to the hwmod @oh during the setup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2428) * process. The IP block is first enabled so it can be successfully
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2429) * reset. Returns 0 upon success or a negative error code upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2430) * failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2431) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2432) static int _setup_reset(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2433) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2434) int r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2436) if (oh->_state != _HWMOD_STATE_INITIALIZED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2437) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2439) if (oh->flags & HWMOD_EXT_OPT_MAIN_CLK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2440) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2442) if (oh->rst_lines_cnt == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2443) r = _enable(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2444) if (r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2445) pr_warn("omap_hwmod: %s: cannot be enabled for reset (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2446) oh->name, oh->_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2447) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2449) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2451) if (!(oh->flags & HWMOD_INIT_NO_RESET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2452) r = _reset(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2454) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2457) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2458) * _setup_postsetup - transition to the appropriate state after _setup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2459) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2460) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2461) * Place an IP block represented by @oh into a "post-setup" state --
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2462) * either IDLE, ENABLED, or DISABLED. ("post-setup" simply means that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2463) * this function is called at the end of _setup().) The postsetup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2464) * state for an IP block can be changed by calling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2465) * omap_hwmod_enter_postsetup_state() early in the boot process,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2466) * before one of the omap_hwmod_setup*() functions are called for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2467) * IP block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2468) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2469) * The IP block stays in this state until a PM runtime-based driver is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2470) * loaded for that IP block. A post-setup state of IDLE is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2471) * appropriate for almost all IP blocks with runtime PM-enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2472) * drivers, since those drivers are able to enable the IP block. A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2473) * post-setup state of ENABLED is appropriate for kernels with PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2474) * runtime disabled. The DISABLED state is appropriate for unusual IP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2475) * blocks such as the MPU WDTIMER on kernels without WDTIMER drivers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2476) * included, since the WDTIMER starts running on reset and will reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2477) * the MPU if left active.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2478) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2479) * This post-setup mechanism is deprecated. Once all of the OMAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2480) * drivers have been converted to use PM runtime, and all of the IP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2481) * block data and interconnect data is available to the hwmod code, it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2482) * should be possible to replace this mechanism with a "lazy reset"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2483) * arrangement. In a "lazy reset" setup, each IP block is enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2484) * when the driver first probes, then all remaining IP blocks without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2485) * drivers are either shut down or enabled after the drivers have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2486) * loaded. However, this cannot take place until the above
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2487) * preconditions have been met, since otherwise the late reset code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2488) * has no way of knowing which IP blocks are in use by drivers, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2489) * which ones are unused.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2490) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2491) * No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2492) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2493) static void _setup_postsetup(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2494) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2495) u8 postsetup_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2497) if (oh->rst_lines_cnt > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2498) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2500) postsetup_state = oh->_postsetup_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2501) if (postsetup_state == _HWMOD_STATE_UNKNOWN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2502) postsetup_state = _HWMOD_STATE_ENABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2504) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2505) * XXX HWMOD_INIT_NO_IDLE does not belong in hwmod data -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2506) * it should be set by the core code as a runtime flag during startup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2507) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2508) if ((oh->flags & (HWMOD_INIT_NO_IDLE | HWMOD_NO_IDLE)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2509) (postsetup_state == _HWMOD_STATE_IDLE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2510) oh->_int_flags |= _HWMOD_SKIP_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2511) postsetup_state = _HWMOD_STATE_ENABLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2512) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2514) if (postsetup_state == _HWMOD_STATE_IDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2515) _idle(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2516) else if (postsetup_state == _HWMOD_STATE_DISABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2517) _shutdown(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2518) else if (postsetup_state != _HWMOD_STATE_ENABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2519) WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2520) oh->name, postsetup_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2522) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2525) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2526) * _setup - prepare IP block hardware for use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2527) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2528) * @n: (unused, pass NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2529) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2530) * Configure the IP block represented by @oh. This may include
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2531) * enabling the IP block, resetting it, and placing it into a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2532) * post-setup state, depending on the type of IP block and applicable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2533) * flags. IP blocks are reset to prevent any previous configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2534) * by the bootloader or previous operating system from interfering
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2535) * with power management or other parts of the system. The reset can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2536) * be avoided; see omap_hwmod_no_setup_reset(). This is the second of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2537) * two phases for hwmod initialization. Code called here generally
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2538) * affects the IP block hardware, or system integration hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2539) * associated with the IP block. Returns 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2540) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2541) static int _setup(struct omap_hwmod *oh, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2543) if (oh->_state != _HWMOD_STATE_INITIALIZED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2544) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2546) if (oh->parent_hwmod) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2547) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2549) r = _enable(oh->parent_hwmod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2550) WARN(r, "hwmod: %s: setup: failed to enable parent hwmod %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2551) oh->name, oh->parent_hwmod->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2552) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2554) _setup_iclk_autoidle(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2556) if (!_setup_reset(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2557) _setup_postsetup(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2559) if (oh->parent_hwmod) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2560) u8 postsetup_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2562) postsetup_state = oh->parent_hwmod->_postsetup_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2564) if (postsetup_state == _HWMOD_STATE_IDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2565) _idle(oh->parent_hwmod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2566) else if (postsetup_state == _HWMOD_STATE_DISABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2567) _shutdown(oh->parent_hwmod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2568) else if (postsetup_state != _HWMOD_STATE_ENABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2569) WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2570) oh->parent_hwmod->name, postsetup_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2573) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2576) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2577) * _register - register a struct omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2578) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2579) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2580) * Registers the omap_hwmod @oh. Returns -EEXIST if an omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2581) * already has been registered by the same name; -EINVAL if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2582) * omap_hwmod is in the wrong state, if @oh is NULL, if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2583) * omap_hwmod's class field is NULL; if the omap_hwmod is missing a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2584) * name, or if the omap_hwmod's class is missing a name; or 0 upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2585) * success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2586) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2587) * XXX The data should be copied into bootmem, so the original data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2588) * should be marked __initdata and freed after init. This would allow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2589) * unneeded omap_hwmods to be freed on multi-OMAP configurations. Note
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2590) * that the copy process would be relatively complex due to the large number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2591) * of substructures.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2592) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2593) static int _register(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2594) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2595) if (!oh || !oh->name || !oh->class || !oh->class->name ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2596) (oh->_state != _HWMOD_STATE_UNKNOWN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2597) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2599) pr_debug("omap_hwmod: %s: registering\n", oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2601) if (_lookup(oh->name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2602) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2604) list_add_tail(&oh->node, &omap_hwmod_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2606) INIT_LIST_HEAD(&oh->slave_ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2607) spin_lock_init(&oh->_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2608) lockdep_set_class(&oh->_lock, &oh->hwmod_key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2610) oh->_state = _HWMOD_STATE_REGISTERED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2612) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2613) * XXX Rather than doing a strcmp(), this should test a flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2614) * set in the hwmod data, inserted by the autogenerator code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2615) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2616) if (!strcmp(oh->name, MPU_INITIATOR_NAME))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2617) mpu_oh = oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2619) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2622) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2623) * _add_link - add an interconnect between two IP blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2624) * @oi: pointer to a struct omap_hwmod_ocp_if record
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2625) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2626) * Add struct omap_hwmod_link records connecting the slave IP block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2627) * specified in @oi->slave to @oi. This code is assumed to run before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2628) * preemption or SMP has been enabled, thus avoiding the need for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2629) * locking in this code. Changes to this assumption will require
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2630) * additional locking. Returns 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2631) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2632) static int _add_link(struct omap_hwmod_ocp_if *oi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2633) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2634) pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2635) oi->slave->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2637) list_add(&oi->node, &oi->slave->slave_ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2638) oi->slave->slaves_cnt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2640) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2643) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2644) * _register_link - register a struct omap_hwmod_ocp_if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2645) * @oi: struct omap_hwmod_ocp_if *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2646) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2647) * Registers the omap_hwmod_ocp_if record @oi. Returns -EEXIST if it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2648) * has already been registered; -EINVAL if @oi is NULL or if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2649) * record pointed to by @oi is missing required fields; or 0 upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2650) * success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2651) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2652) * XXX The data should be copied into bootmem, so the original data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2653) * should be marked __initdata and freed after init. This would allow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2654) * unneeded omap_hwmods to be freed on multi-OMAP configurations.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2655) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2656) static int __init _register_link(struct omap_hwmod_ocp_if *oi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2657) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2658) if (!oi || !oi->master || !oi->slave || !oi->user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2659) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2661) if (oi->_int_flags & _OCPIF_INT_FLAGS_REGISTERED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2662) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2664) pr_debug("omap_hwmod: registering link from %s to %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2665) oi->master->name, oi->slave->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2667) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2668) * Register the connected hwmods, if they haven't been
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2669) * registered already
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2670) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2671) if (oi->master->_state != _HWMOD_STATE_REGISTERED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2672) _register(oi->master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2674) if (oi->slave->_state != _HWMOD_STATE_REGISTERED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2675) _register(oi->slave);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2677) _add_link(oi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2679) oi->_int_flags |= _OCPIF_INT_FLAGS_REGISTERED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2681) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2684) /* Static functions intended only for use in soc_ops field function pointers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2686) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2687) * _omap2xxx_3xxx_wait_target_ready - wait for a module to leave slave idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2688) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2689) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2690) * Wait for a module @oh to leave slave idle. Returns 0 if the module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2691) * does not have an IDLEST bit or if the module successfully leaves
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2692) * slave idle; otherwise, pass along the return value of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2693) * appropriate *_cm*_wait_module_ready() function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2694) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2695) static int _omap2xxx_3xxx_wait_target_ready(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2696) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2697) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2698) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2700) if (oh->flags & HWMOD_NO_IDLEST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2701) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2703) if (!_find_mpu_rt_port(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2704) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2706) /* XXX check module SIDLEMODE, hardreset status, enabled clocks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2708) return omap_cm_wait_module_ready(0, oh->prcm.omap2.module_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2709) oh->prcm.omap2.idlest_reg_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2710) oh->prcm.omap2.idlest_idle_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2711) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2713) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2714) * _omap4_wait_target_ready - wait for a module to leave slave idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2715) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2716) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2717) * Wait for a module @oh to leave slave idle. Returns 0 if the module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2718) * does not have an IDLEST bit or if the module successfully leaves
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2719) * slave idle; otherwise, pass along the return value of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2720) * appropriate *_cm*_wait_module_ready() function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2721) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2722) static int _omap4_wait_target_ready(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2723) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2724) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2725) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2727) if (oh->flags & HWMOD_NO_IDLEST || !oh->clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2728) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2730) if (!_find_mpu_rt_port(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2731) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2733) if (_omap4_clkctrl_managed_by_clkfwk(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2734) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2736) if (!_omap4_has_clkctrl_clock(oh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2737) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2739) /* XXX check module SIDLEMODE, hardreset status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2741) return omap_cm_wait_module_ready(oh->clkdm->prcm_partition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2742) oh->clkdm->cm_inst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2743) oh->prcm.omap4.clkctrl_offs, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2744) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2745)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2746) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2747) * _omap2_assert_hardreset - call OMAP2 PRM hardreset fn with hwmod args
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2748) * @oh: struct omap_hwmod * to assert hardreset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2749) * @ohri: hardreset line data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2750) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2751) * Call omap2_prm_assert_hardreset() with parameters extracted from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2752) * the hwmod @oh and the hardreset line data @ohri. Only intended for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2753) * use as an soc_ops function pointer. Passes along the return value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2754) * from omap2_prm_assert_hardreset(). XXX This function is scheduled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2755) * for removal when the PRM code is moved into drivers/.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2756) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2757) static int _omap2_assert_hardreset(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2758) struct omap_hwmod_rst_info *ohri)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2759) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2760) return omap_prm_assert_hardreset(ohri->rst_shift, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2761) oh->prcm.omap2.module_offs, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2764) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2765) * _omap2_deassert_hardreset - call OMAP2 PRM hardreset fn with hwmod args
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2766) * @oh: struct omap_hwmod * to deassert hardreset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2767) * @ohri: hardreset line data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2768) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2769) * Call omap2_prm_deassert_hardreset() with parameters extracted from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2770) * the hwmod @oh and the hardreset line data @ohri. Only intended for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2771) * use as an soc_ops function pointer. Passes along the return value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2772) * from omap2_prm_deassert_hardreset(). XXX This function is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2773) * scheduled for removal when the PRM code is moved into drivers/.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2774) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2775) static int _omap2_deassert_hardreset(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2776) struct omap_hwmod_rst_info *ohri)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2777) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2778) return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2779) oh->prcm.omap2.module_offs, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2780) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2782) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2783) * _omap2_is_hardreset_asserted - call OMAP2 PRM hardreset fn with hwmod args
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2784) * @oh: struct omap_hwmod * to test hardreset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2785) * @ohri: hardreset line data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2786) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2787) * Call omap2_prm_is_hardreset_asserted() with parameters extracted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2788) * from the hwmod @oh and the hardreset line data @ohri. Only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2789) * intended for use as an soc_ops function pointer. Passes along the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2790) * return value from omap2_prm_is_hardreset_asserted(). XXX This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2791) * function is scheduled for removal when the PRM code is moved into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2792) * drivers/.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2793) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2794) static int _omap2_is_hardreset_asserted(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2795) struct omap_hwmod_rst_info *ohri)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2796) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2797) return omap_prm_is_hardreset_asserted(ohri->st_shift, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2798) oh->prcm.omap2.module_offs, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2799) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2801) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2802) * _omap4_assert_hardreset - call OMAP4 PRM hardreset fn with hwmod args
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2803) * @oh: struct omap_hwmod * to assert hardreset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2804) * @ohri: hardreset line data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2805) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2806) * Call omap4_prminst_assert_hardreset() with parameters extracted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2807) * from the hwmod @oh and the hardreset line data @ohri. Only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2808) * intended for use as an soc_ops function pointer. Passes along the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2809) * return value from omap4_prminst_assert_hardreset(). XXX This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2810) * function is scheduled for removal when the PRM code is moved into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2811) * drivers/.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2812) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2813) static int _omap4_assert_hardreset(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2814) struct omap_hwmod_rst_info *ohri)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2815) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2816) if (!oh->clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2817) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2819) return omap_prm_assert_hardreset(ohri->rst_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2820) oh->clkdm->pwrdm.ptr->prcm_partition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2821) oh->clkdm->pwrdm.ptr->prcm_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2822) oh->prcm.omap4.rstctrl_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2825) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2826) * _omap4_deassert_hardreset - call OMAP4 PRM hardreset fn with hwmod args
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2827) * @oh: struct omap_hwmod * to deassert hardreset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2828) * @ohri: hardreset line data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2829) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2830) * Call omap4_prminst_deassert_hardreset() with parameters extracted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2831) * from the hwmod @oh and the hardreset line data @ohri. Only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2832) * intended for use as an soc_ops function pointer. Passes along the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2833) * return value from omap4_prminst_deassert_hardreset(). XXX This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2834) * function is scheduled for removal when the PRM code is moved into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2835) * drivers/.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2836) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2837) static int _omap4_deassert_hardreset(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2838) struct omap_hwmod_rst_info *ohri)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2839) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2840) if (!oh->clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2841) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2843) if (ohri->st_shift)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2844) pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2845) oh->name, ohri->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2846) return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->rst_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2847) oh->clkdm->pwrdm.ptr->prcm_partition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2848) oh->clkdm->pwrdm.ptr->prcm_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2849) oh->prcm.omap4.rstctrl_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2850) oh->prcm.omap4.rstctrl_offs +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2851) OMAP4_RST_CTRL_ST_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2852) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2854) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2855) * _omap4_is_hardreset_asserted - call OMAP4 PRM hardreset fn with hwmod args
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2856) * @oh: struct omap_hwmod * to test hardreset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2857) * @ohri: hardreset line data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2858) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2859) * Call omap4_prminst_is_hardreset_asserted() with parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2860) * extracted from the hwmod @oh and the hardreset line data @ohri.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2861) * Only intended for use as an soc_ops function pointer. Passes along
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2862) * the return value from omap4_prminst_is_hardreset_asserted(). XXX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2863) * This function is scheduled for removal when the PRM code is moved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2864) * into drivers/.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2865) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2866) static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2867) struct omap_hwmod_rst_info *ohri)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2868) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2869) if (!oh->clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2870) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2872) return omap_prm_is_hardreset_asserted(ohri->rst_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2873) oh->clkdm->pwrdm.ptr->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2874) prcm_partition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2875) oh->clkdm->pwrdm.ptr->prcm_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2876) oh->prcm.omap4.rstctrl_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2877) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2879) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2880) * _omap4_disable_direct_prcm - disable direct PRCM control for hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2881) * @oh: struct omap_hwmod * to disable control for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2882) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2883) * Disables direct PRCM clkctrl done by hwmod core. Instead, the hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2884) * will be using its main_clk to enable/disable the module. Returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2885) * 0 if successful.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2886) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2887) static int _omap4_disable_direct_prcm(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2888) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2889) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2890) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2892) oh->prcm.omap4.flags |= HWMOD_OMAP4_CLKFWK_CLKCTR_CLOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2894) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2895) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2897) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2898) * _am33xx_deassert_hardreset - call AM33XX PRM hardreset fn with hwmod args
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2899) * @oh: struct omap_hwmod * to deassert hardreset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2900) * @ohri: hardreset line data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2901) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2902) * Call am33xx_prminst_deassert_hardreset() with parameters extracted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2903) * from the hwmod @oh and the hardreset line data @ohri. Only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2904) * intended for use as an soc_ops function pointer. Passes along the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2905) * return value from am33xx_prminst_deassert_hardreset(). XXX This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2906) * function is scheduled for removal when the PRM code is moved into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2907) * drivers/.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2908) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2909) static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2910) struct omap_hwmod_rst_info *ohri)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2911) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2912) return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2913) oh->clkdm->pwrdm.ptr->prcm_partition,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2914) oh->clkdm->pwrdm.ptr->prcm_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2915) oh->prcm.omap4.rstctrl_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2916) oh->prcm.omap4.rstst_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2917) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2919) /* Public functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2921) u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2922) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2923) if (oh->flags & HWMOD_16BIT_REG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2924) return readw_relaxed(oh->_mpu_rt_va + reg_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2925) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2926) return readl_relaxed(oh->_mpu_rt_va + reg_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2927) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2929) void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2930) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2931) if (oh->flags & HWMOD_16BIT_REG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2932) writew_relaxed(v, oh->_mpu_rt_va + reg_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2933) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2934) writel_relaxed(v, oh->_mpu_rt_va + reg_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2935) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2937) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2938) * omap_hwmod_softreset - reset a module via SYSCONFIG.SOFTRESET bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2939) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2940) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2941) * This is a public function exposed to drivers. Some drivers may need to do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2942) * some settings before and after resetting the device. Those drivers after
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2943) * doing the necessary settings could use this function to start a reset by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2944) * setting the SYSCONFIG.SOFTRESET bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2945) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2946) int omap_hwmod_softreset(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2947) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2948) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2949) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2951) if (!oh || !(oh->_sysc_cache))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2952) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2954) v = oh->_sysc_cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2955) ret = _set_softreset(oh, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2956) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2957) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2958) _write_sysconfig(v, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2960) ret = _clear_softreset(oh, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2961) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2962) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2963) _write_sysconfig(v, oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2965) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2966) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2967) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2969) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2970) * omap_hwmod_lookup - look up a registered omap_hwmod by name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2971) * @name: name of the omap_hwmod to look up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2972) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2973) * Given a @name of an omap_hwmod, return a pointer to the registered
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2974) * struct omap_hwmod *, or NULL upon error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2975) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2976) struct omap_hwmod *omap_hwmod_lookup(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2977) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2978) struct omap_hwmod *oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2980) if (!name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2981) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2983) oh = _lookup(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2985) return oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2986) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2988) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2989) * omap_hwmod_for_each - call function for each registered omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2990) * @fn: pointer to a callback function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2991) * @data: void * data to pass to callback function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2992) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2993) * Call @fn for each registered omap_hwmod, passing @data to each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2994) * function. @fn must return 0 for success or any other value for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2995) * failure. If @fn returns non-zero, the iteration across omap_hwmods
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2996) * will stop and the non-zero return value will be passed to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2997) * caller of omap_hwmod_for_each(). @fn is called with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2998) * omap_hwmod_for_each() held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2999) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3000) int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3001) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3002) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3003) struct omap_hwmod *temp_oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3004) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3005)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3006) if (!fn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3007) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3009) list_for_each_entry(temp_oh, &omap_hwmod_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3010) ret = (*fn)(temp_oh, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3011) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3012) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3013) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3015) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3016) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3017)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3018) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3019) * omap_hwmod_register_links - register an array of hwmod links
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3020) * @ois: pointer to an array of omap_hwmod_ocp_if to register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3021) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3022) * Intended to be called early in boot before the clock framework is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3023) * initialized. If @ois is not null, will register all omap_hwmods
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3024) * listed in @ois that are valid for this chip. Returns -EINVAL if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3025) * omap_hwmod_init() hasn't been called before calling this function,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3026) * -ENOMEM if the link memory area can't be allocated, or 0 upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3027) * success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3028) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3029) int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3030) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3031) int r, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3033) if (!inited)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3034) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3035)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3036) if (!ois)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3037) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3039) if (ois[0] == NULL) /* Empty list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3040) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3042) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3043) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3044) r = _register_link(ois[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3045) WARN(r && r != -EEXIST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3046) "omap_hwmod: _register_link(%s -> %s) returned %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3047) ois[i]->master->name, ois[i]->slave->name, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3048) } while (ois[++i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3050) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3051) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3053) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3054) * _ensure_mpu_hwmod_is_setup - ensure the MPU SS hwmod is init'ed and set up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3055) * @oh: pointer to the hwmod currently being set up (usually not the MPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3056) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3057) * If the hwmod data corresponding to the MPU subsystem IP block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3058) * hasn't been initialized and set up yet, do so now. This must be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3059) * done first since sleep dependencies may be added from other hwmods
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3060) * to the MPU. Intended to be called only by omap_hwmod_setup*(). No
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3061) * return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3062) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3063) static void __init _ensure_mpu_hwmod_is_setup(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3064) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3065) if (!mpu_oh || mpu_oh->_state == _HWMOD_STATE_UNKNOWN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3066) pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3067) __func__, MPU_INITIATOR_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3068) else if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3069) omap_hwmod_setup_one(MPU_INITIATOR_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3070) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3072) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3073) * omap_hwmod_setup_one - set up a single hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3074) * @oh_name: const char * name of the already-registered hwmod to set up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3075) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3076) * Initialize and set up a single hwmod. Intended to be used for a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3077) * small number of early devices, such as the timer IP blocks used for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3078) * the scheduler clock. Must be called after omap2_clk_init().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3079) * Resolves the struct clk names to struct clk pointers for each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3080) * registered omap_hwmod. Also calls _setup() on each hwmod. Returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3081) * -EINVAL upon error or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3082) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3083) int __init omap_hwmod_setup_one(const char *oh_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3084) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3085) struct omap_hwmod *oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3087) pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3089) oh = _lookup(oh_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3090) if (!oh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3091) WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3092) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3093) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3095) _ensure_mpu_hwmod_is_setup(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3097) _init(oh, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3098) _setup(oh, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3099)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3100) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3103) static void omap_hwmod_check_one(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3104) const char *name, s8 v1, u8 v2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3106) if (v1 < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3107) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3109) if (v1 != v2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3110) dev_warn(dev, "%s %d != %d\n", name, v1, v2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3113) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3114) * omap_hwmod_check_sysc - check sysc against platform sysc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3115) * @dev: struct device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3116) * @data: module data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3117) * @sysc_fields: new sysc configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3119) static int omap_hwmod_check_sysc(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3120) const struct ti_sysc_module_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3121) struct sysc_regbits *sysc_fields)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3123) const struct sysc_regbits *regbits = data->cap->regbits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3125) omap_hwmod_check_one(dev, "dmadisable_shift",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3126) regbits->dmadisable_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3127) sysc_fields->dmadisable_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3128) omap_hwmod_check_one(dev, "midle_shift",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3129) regbits->midle_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3130) sysc_fields->midle_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3131) omap_hwmod_check_one(dev, "sidle_shift",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3132) regbits->sidle_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3133) sysc_fields->sidle_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3134) omap_hwmod_check_one(dev, "clkact_shift",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3135) regbits->clkact_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3136) sysc_fields->clkact_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3137) omap_hwmod_check_one(dev, "enwkup_shift",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3138) regbits->enwkup_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3139) sysc_fields->enwkup_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3140) omap_hwmod_check_one(dev, "srst_shift",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3141) regbits->srst_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3142) sysc_fields->srst_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3143) omap_hwmod_check_one(dev, "autoidle_shift",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3144) regbits->autoidle_shift,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3145) sysc_fields->autoidle_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3147) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3150) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3151) * omap_hwmod_init_regbits - init sysconfig specific register bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3152) * @dev: struct device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3153) * @oh: module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3154) * @data: module data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3155) * @sysc_fields: new sysc configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3156) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3157) static int omap_hwmod_init_regbits(struct device *dev, struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3158) const struct ti_sysc_module_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3159) struct sysc_regbits **sysc_fields)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3161) switch (data->cap->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3162) case TI_SYSC_OMAP2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3163) case TI_SYSC_OMAP2_TIMER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3164) *sysc_fields = &omap_hwmod_sysc_type1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3165) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3166) case TI_SYSC_OMAP3_SHAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3167) *sysc_fields = &omap3_sham_sysc_fields;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3168) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3169) case TI_SYSC_OMAP3_AES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3170) *sysc_fields = &omap3xxx_aes_sysc_fields;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3171) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3172) case TI_SYSC_OMAP4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3173) case TI_SYSC_OMAP4_TIMER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3174) *sysc_fields = &omap_hwmod_sysc_type2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3175) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3176) case TI_SYSC_OMAP4_SIMPLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3177) *sysc_fields = &omap_hwmod_sysc_type3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3178) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3179) case TI_SYSC_OMAP34XX_SR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3180) *sysc_fields = &omap34xx_sr_sysc_fields;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3181) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3182) case TI_SYSC_OMAP36XX_SR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3183) *sysc_fields = &omap36xx_sr_sysc_fields;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3184) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3185) case TI_SYSC_OMAP4_SR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3186) *sysc_fields = &omap36xx_sr_sysc_fields;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3187) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3188) case TI_SYSC_OMAP4_MCASP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3189) *sysc_fields = &omap_hwmod_sysc_type_mcasp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3190) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3191) case TI_SYSC_OMAP4_USB_HOST_FS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3192) *sysc_fields = &omap_hwmod_sysc_type_usb_host_fs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3193) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3194) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3195) *sysc_fields = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3196) if (!oh->class->sysc->sysc_fields)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3199) dev_err(dev, "sysc_fields not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3201) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3204) return omap_hwmod_check_sysc(dev, data, *sysc_fields);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3207) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3208) * omap_hwmod_init_reg_offs - initialize sysconfig register offsets
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3209) * @dev: struct device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3210) * @data: module data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3211) * @rev_offs: revision register offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3212) * @sysc_offs: sysc register offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3213) * @syss_offs: syss register offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3214) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3215) static int omap_hwmod_init_reg_offs(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3216) const struct ti_sysc_module_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3217) s32 *rev_offs, s32 *sysc_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3218) s32 *syss_offs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3220) *rev_offs = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3221) *sysc_offs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3222) *syss_offs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3224) if (data->offsets[SYSC_REVISION] >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3225) *rev_offs = data->offsets[SYSC_REVISION];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3227) if (data->offsets[SYSC_SYSCONFIG] >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3228) *sysc_offs = data->offsets[SYSC_SYSCONFIG];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3230) if (data->offsets[SYSC_SYSSTATUS] >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3231) *syss_offs = data->offsets[SYSC_SYSSTATUS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3233) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3236) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3237) * omap_hwmod_init_sysc_flags - initialize sysconfig features
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3238) * @dev: struct device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3239) * @data: module data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3240) * @sysc_flags: module configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3241) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3242) static int omap_hwmod_init_sysc_flags(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3243) const struct ti_sysc_module_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3244) u32 *sysc_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3246) *sysc_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3248) switch (data->cap->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3249) case TI_SYSC_OMAP2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3250) case TI_SYSC_OMAP2_TIMER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3251) /* See SYSC_OMAP2_* in include/dt-bindings/bus/ti-sysc.h */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3252) if (data->cfg->sysc_val & SYSC_OMAP2_CLOCKACTIVITY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3253) *sysc_flags |= SYSC_HAS_CLOCKACTIVITY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3254) if (data->cfg->sysc_val & SYSC_OMAP2_EMUFREE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3255) *sysc_flags |= SYSC_HAS_EMUFREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3256) if (data->cfg->sysc_val & SYSC_OMAP2_ENAWAKEUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3257) *sysc_flags |= SYSC_HAS_ENAWAKEUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3258) if (data->cfg->sysc_val & SYSC_OMAP2_SOFTRESET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3259) *sysc_flags |= SYSC_HAS_SOFTRESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3260) if (data->cfg->sysc_val & SYSC_OMAP2_AUTOIDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3261) *sysc_flags |= SYSC_HAS_AUTOIDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3262) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3263) case TI_SYSC_OMAP4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3264) case TI_SYSC_OMAP4_TIMER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3265) /* See SYSC_OMAP4_* in include/dt-bindings/bus/ti-sysc.h */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3266) if (data->cfg->sysc_val & SYSC_OMAP4_DMADISABLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3267) *sysc_flags |= SYSC_HAS_DMADISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3268) if (data->cfg->sysc_val & SYSC_OMAP4_FREEEMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3269) *sysc_flags |= SYSC_HAS_EMUFREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3270) if (data->cfg->sysc_val & SYSC_OMAP4_SOFTRESET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3271) *sysc_flags |= SYSC_HAS_SOFTRESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3272) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3273) case TI_SYSC_OMAP34XX_SR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3274) case TI_SYSC_OMAP36XX_SR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3275) /* See SYSC_OMAP3_SR_* in include/dt-bindings/bus/ti-sysc.h */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3276) if (data->cfg->sysc_val & SYSC_OMAP3_SR_ENAWAKEUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3277) *sysc_flags |= SYSC_HAS_ENAWAKEUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3278) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3279) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3280) if (data->cap->regbits->emufree_shift >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3281) *sysc_flags |= SYSC_HAS_EMUFREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3282) if (data->cap->regbits->enwkup_shift >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3283) *sysc_flags |= SYSC_HAS_ENAWAKEUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3284) if (data->cap->regbits->srst_shift >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3285) *sysc_flags |= SYSC_HAS_SOFTRESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3286) if (data->cap->regbits->autoidle_shift >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3287) *sysc_flags |= SYSC_HAS_AUTOIDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3288) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3291) if (data->cap->regbits->midle_shift >= 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3292) data->cfg->midlemodes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3293) *sysc_flags |= SYSC_HAS_MIDLEMODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3295) if (data->cap->regbits->sidle_shift >= 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3296) data->cfg->sidlemodes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3297) *sysc_flags |= SYSC_HAS_SIDLEMODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3299) if (data->cfg->quirks & SYSC_QUIRK_UNCACHED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3300) *sysc_flags |= SYSC_NO_CACHE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3301) if (data->cfg->quirks & SYSC_QUIRK_RESET_STATUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3302) *sysc_flags |= SYSC_HAS_RESET_STATUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3304) if (data->cfg->syss_mask & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3305) *sysc_flags |= SYSS_HAS_RESET_STATUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3307) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3310) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3311) * omap_hwmod_init_idlemodes - initialize module idle modes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3312) * @dev: struct device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3313) * @data: module data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3314) * @idlemodes: module supported idle modes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3315) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3316) static int omap_hwmod_init_idlemodes(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3317) const struct ti_sysc_module_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3318) u32 *idlemodes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3319) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3320) *idlemodes = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3322) if (data->cfg->midlemodes & BIT(SYSC_IDLE_FORCE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3323) *idlemodes |= MSTANDBY_FORCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3324) if (data->cfg->midlemodes & BIT(SYSC_IDLE_NO))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3325) *idlemodes |= MSTANDBY_NO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3326) if (data->cfg->midlemodes & BIT(SYSC_IDLE_SMART))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3327) *idlemodes |= MSTANDBY_SMART;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3328) if (data->cfg->midlemodes & BIT(SYSC_IDLE_SMART_WKUP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3329) *idlemodes |= MSTANDBY_SMART_WKUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3331) if (data->cfg->sidlemodes & BIT(SYSC_IDLE_FORCE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3332) *idlemodes |= SIDLE_FORCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3333) if (data->cfg->sidlemodes & BIT(SYSC_IDLE_NO))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3334) *idlemodes |= SIDLE_NO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3335) if (data->cfg->sidlemodes & BIT(SYSC_IDLE_SMART))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3336) *idlemodes |= SIDLE_SMART;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3337) if (data->cfg->sidlemodes & BIT(SYSC_IDLE_SMART_WKUP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3338) *idlemodes |= SIDLE_SMART_WKUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3340) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3343) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3344) * omap_hwmod_check_module - check new module against platform data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3345) * @dev: struct device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3346) * @oh: module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3347) * @data: new module data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3348) * @sysc_fields: sysc register bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3349) * @rev_offs: revision register offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3350) * @sysc_offs: sysconfig register offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3351) * @syss_offs: sysstatus register offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3352) * @sysc_flags: sysc specific flags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3353) * @idlemodes: sysc supported idlemodes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3354) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3355) static int omap_hwmod_check_module(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3356) struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3357) const struct ti_sysc_module_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3358) struct sysc_regbits *sysc_fields,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3359) s32 rev_offs, s32 sysc_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3360) s32 syss_offs, u32 sysc_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3361) u32 idlemodes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3362) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3363) if (!oh->class->sysc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3364) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3366) if (oh->class->sysc->sysc_fields &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3367) sysc_fields != oh->class->sysc->sysc_fields)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3368) dev_warn(dev, "sysc_fields mismatch\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3370) if (rev_offs != oh->class->sysc->rev_offs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3371) dev_warn(dev, "rev_offs %08x != %08x\n", rev_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3372) oh->class->sysc->rev_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3373) if (sysc_offs != oh->class->sysc->sysc_offs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3374) dev_warn(dev, "sysc_offs %08x != %08x\n", sysc_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3375) oh->class->sysc->sysc_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3376) if (syss_offs != oh->class->sysc->syss_offs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3377) dev_warn(dev, "syss_offs %08x != %08x\n", syss_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3378) oh->class->sysc->syss_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3380) if (sysc_flags != oh->class->sysc->sysc_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3381) dev_warn(dev, "sysc_flags %08x != %08x\n", sysc_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3382) oh->class->sysc->sysc_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3384) if (idlemodes != oh->class->sysc->idlemodes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3385) dev_warn(dev, "idlemodes %08x != %08x\n", idlemodes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3386) oh->class->sysc->idlemodes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3388) if (data->cfg->srst_udelay != oh->class->sysc->srst_udelay)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3389) dev_warn(dev, "srst_udelay %i != %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3390) data->cfg->srst_udelay,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3391) oh->class->sysc->srst_udelay);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3393) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3396) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3397) * omap_hwmod_allocate_module - allocate new module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3398) * @dev: struct device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3399) * @oh: module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3400) * @sysc_fields: sysc register bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3401) * @clockdomain: clockdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3402) * @rev_offs: revision register offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3403) * @sysc_offs: sysconfig register offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3404) * @syss_offs: sysstatus register offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3405) * @sysc_flags: sysc specific flags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3406) * @idlemodes: sysc supported idlemodes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3407) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3408) * Note that the allocations here cannot use devm as ti-sysc can rebind.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3409) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3410) static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3411) const struct ti_sysc_module_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3412) struct sysc_regbits *sysc_fields,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3413) struct clockdomain *clkdm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3414) s32 rev_offs, s32 sysc_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3415) s32 syss_offs, u32 sysc_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3416) u32 idlemodes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3417) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3418) struct omap_hwmod_class_sysconfig *sysc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3419) struct omap_hwmod_class *class = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3420) struct omap_hwmod_ocp_if *oi = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3421) void __iomem *regs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3422) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3424) sysc = kzalloc(sizeof(*sysc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3425) if (!sysc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3426) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3428) sysc->sysc_fields = sysc_fields;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3429) sysc->rev_offs = rev_offs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3430) sysc->sysc_offs = sysc_offs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3431) sysc->syss_offs = syss_offs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3432) sysc->sysc_flags = sysc_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3433) sysc->idlemodes = idlemodes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3434) sysc->srst_udelay = data->cfg->srst_udelay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3436) if (!oh->_mpu_rt_va) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3437) regs = ioremap(data->module_pa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3438) data->module_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3439) if (!regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3440) goto out_free_sysc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3443) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3444) * We may need a new oh->class as the other devices in the same class
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3445) * may not yet have ioremapped their registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3446) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3447) if (oh->class->name && strcmp(oh->class->name, data->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3448) class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3449) if (!class)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3450) goto out_unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3453) if (list_empty(&oh->slave_ports)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3454) oi = kcalloc(1, sizeof(*oi), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3455) if (!oi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3456) goto out_free_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3458) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3459) * Note that we assume interconnect interface clocks will be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3460) * managed by the interconnect driver for OCPIF_SWSUP_IDLE case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3461) * on omap24xx and omap3.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3462) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3463) oi->slave = oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3464) oi->user = OCP_USER_MPU | OCP_USER_SDMA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3467) spin_lock_irqsave(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3468) if (regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3469) oh->_mpu_rt_va = regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3470) if (class)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3471) oh->class = class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3472) oh->class->sysc = sysc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3473) if (oi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3474) _add_link(oi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3475) if (clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3476) oh->clkdm = clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3477) oh->_state = _HWMOD_STATE_INITIALIZED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3478) oh->_postsetup_state = _HWMOD_STATE_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3479) _setup(oh, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3480) spin_unlock_irqrestore(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3482) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3484) out_free_class:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3485) kfree(class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3486) out_unmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3487) iounmap(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3488) out_free_sysc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3489) kfree(sysc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3490) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3493) static const struct omap_hwmod_reset omap24xx_reset_quirks[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3494) { .match = "msdi", .len = 4, .reset = omap_msdi_reset, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3495) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3497) static const struct omap_hwmod_reset dra7_reset_quirks[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3498) { .match = "pcie", .len = 4, .reset = dra7xx_pciess_reset, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3499) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3501) static const struct omap_hwmod_reset omap_reset_quirks[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3502) { .match = "dss_core", .len = 8, .reset = omap_dss_reset, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3503) { .match = "hdq1w", .len = 5, .reset = omap_hdq1w_reset, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3504) { .match = "i2c", .len = 3, .reset = omap_i2c_reset, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3505) { .match = "wd_timer", .len = 8, .reset = omap2_wd_timer_reset, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3506) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3508) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3509) omap_hwmod_init_reset_quirk(struct device *dev, struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3510) const struct ti_sysc_module_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3511) const struct omap_hwmod_reset *quirks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3512) int quirks_sz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3514) const struct omap_hwmod_reset *quirk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3515) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3517) for (i = 0; i < quirks_sz; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3518) quirk = &quirks[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3519) if (!strncmp(data->name, quirk->match, quirk->len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3520) oh->class->reset = quirk->reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3522) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3527) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3528) omap_hwmod_init_reset_quirks(struct device *dev, struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3529) const struct ti_sysc_module_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3530) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3531) if (soc_is_omap24xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3532) omap_hwmod_init_reset_quirk(dev, oh, data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3533) omap24xx_reset_quirks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3534) ARRAY_SIZE(omap24xx_reset_quirks));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3536) if (soc_is_dra7xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3537) omap_hwmod_init_reset_quirk(dev, oh, data, dra7_reset_quirks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3538) ARRAY_SIZE(dra7_reset_quirks));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3540) omap_hwmod_init_reset_quirk(dev, oh, data, omap_reset_quirks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3541) ARRAY_SIZE(omap_reset_quirks));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3544) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3545) * omap_hwmod_init_module - initialize new module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3546) * @dev: struct device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3547) * @data: module data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3548) * @cookie: cookie for the caller to use for later calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3549) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3550) int omap_hwmod_init_module(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3551) const struct ti_sysc_module_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3552) struct ti_sysc_cookie *cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3553) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3554) struct omap_hwmod *oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3555) struct sysc_regbits *sysc_fields;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3556) s32 rev_offs, sysc_offs, syss_offs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3557) u32 sysc_flags, idlemodes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3558) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3560) if (!dev || !data || !data->name || !cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3561) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3563) oh = _lookup(data->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3564) if (!oh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3565) oh = kzalloc(sizeof(*oh), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3566) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3567) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3569) oh->name = data->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3570) oh->_state = _HWMOD_STATE_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3571) lockdep_register_key(&oh->hwmod_key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3573) /* Unused, can be handled by PRM driver handling resets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3574) oh->prcm.omap4.flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3576) oh->class = kzalloc(sizeof(*oh->class), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3577) if (!oh->class) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3578) kfree(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3579) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3582) omap_hwmod_init_reset_quirks(dev, oh, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3584) oh->class->name = data->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3585) mutex_lock(&list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3586) error = _register(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3587) mutex_unlock(&list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3590) cookie->data = oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3592) error = omap_hwmod_init_regbits(dev, oh, data, &sysc_fields);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3593) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3594) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3596) error = omap_hwmod_init_reg_offs(dev, data, &rev_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3597) &sysc_offs, &syss_offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3598) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3599) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3601) error = omap_hwmod_init_sysc_flags(dev, data, &sysc_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3602) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3603) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3605) error = omap_hwmod_init_idlemodes(dev, data, &idlemodes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3606) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3607) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3609) if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3610) oh->flags |= HWMOD_NO_IDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3611) if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE_ON_INIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3612) oh->flags |= HWMOD_INIT_NO_IDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3613) if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3614) oh->flags |= HWMOD_INIT_NO_RESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3615) if (data->cfg->quirks & SYSC_QUIRK_USE_CLOCKACT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3616) oh->flags |= HWMOD_SET_DEFAULT_CLOCKACT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3617) if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3618) oh->flags |= HWMOD_SWSUP_SIDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3619) if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE_ACT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3620) oh->flags |= HWMOD_SWSUP_SIDLE_ACT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3621) if (data->cfg->quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3622) oh->flags |= HWMOD_SWSUP_MSTANDBY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3623) if (data->cfg->quirks & SYSC_QUIRK_CLKDM_NOAUTO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3624) oh->flags |= HWMOD_CLKDM_NOAUTO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3626) error = omap_hwmod_check_module(dev, oh, data, sysc_fields,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3627) rev_offs, sysc_offs, syss_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3628) sysc_flags, idlemodes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3629) if (!error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3630) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3632) return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3633) cookie->clkdm, rev_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3634) sysc_offs, syss_offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3635) sysc_flags, idlemodes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3638) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3639) * omap_hwmod_setup_earlycon_flags - set up flags for early console
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3640) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3641) * Enable DEBUG_OMAPUART_FLAGS for uart hwmod that is being used as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3642) * early concole so that hwmod core doesn't reset and keep it in idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3643) * that specific uart.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3644) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3645) #ifdef CONFIG_SERIAL_EARLYCON
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3646) static void __init omap_hwmod_setup_earlycon_flags(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3648) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3649) struct omap_hwmod *oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3650) const char *uart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3652) np = of_find_node_by_path("/chosen");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3653) if (np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3654) uart = of_get_property(np, "stdout-path", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3655) if (uart) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3656) np = of_find_node_by_path(uart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3657) if (np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3658) uart = of_get_property(np, "ti,hwmods", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3659) oh = omap_hwmod_lookup(uart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3660) if (!oh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3661) uart = of_get_property(np->parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3662) "ti,hwmods",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3663) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3664) oh = omap_hwmod_lookup(uart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3666) if (oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3667) oh->flags |= DEBUG_OMAPUART_FLAGS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3668) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3669) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3670) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3672) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3674) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3675) * omap_hwmod_setup_all - set up all registered IP blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3676) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3677) * Initialize and set up all IP blocks registered with the hwmod code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3678) * Must be called after omap2_clk_init(). Resolves the struct clk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3679) * names to struct clk pointers for each registered omap_hwmod. Also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3680) * calls _setup() on each hwmod. Returns 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3681) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3682) static int __init omap_hwmod_setup_all(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3683) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3684) _ensure_mpu_hwmod_is_setup(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3686) omap_hwmod_for_each(_init, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3687) #ifdef CONFIG_SERIAL_EARLYCON
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3688) omap_hwmod_setup_earlycon_flags();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3689) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3690) omap_hwmod_for_each(_setup, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3692) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3694) omap_postcore_initcall(omap_hwmod_setup_all);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3696) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3697) * omap_hwmod_enable - enable an omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3698) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3699) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3700) * Enable an omap_hwmod @oh. Intended to be called by omap_device_enable().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3701) * Returns -EINVAL on error or passes along the return value from _enable().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3702) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3703) int omap_hwmod_enable(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3704) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3705) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3706) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3708) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3709) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3711) spin_lock_irqsave(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3712) r = _enable(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3713) spin_unlock_irqrestore(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3715) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3716) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3718) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3719) * omap_hwmod_idle - idle an omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3720) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3721) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3722) * Idle an omap_hwmod @oh. Intended to be called by omap_device_idle().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3723) * Returns -EINVAL on error or passes along the return value from _idle().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3724) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3725) int omap_hwmod_idle(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3726) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3727) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3728) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3730) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3731) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3733) spin_lock_irqsave(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3734) r = _idle(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3735) spin_unlock_irqrestore(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3737) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3740) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3741) * omap_hwmod_shutdown - shutdown an omap_hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3742) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3743) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3744) * Shutdown an omap_hwmod @oh. Intended to be called by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3745) * omap_device_shutdown(). Returns -EINVAL on error or passes along
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3746) * the return value from _shutdown().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3747) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3748) int omap_hwmod_shutdown(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3749) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3750) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3751) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3753) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3754) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3756) spin_lock_irqsave(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3757) r = _shutdown(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3758) spin_unlock_irqrestore(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3760) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3761) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3763) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3764) * IP block data retrieval functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3765) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3767) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3768) * omap_hwmod_get_pwrdm - return pointer to this module's main powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3769) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3770) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3771) * Return the powerdomain pointer associated with the OMAP module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3772) * @oh's main clock. If @oh does not have a main clk, return the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3773) * powerdomain associated with the interface clock associated with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3774) * module's MPU port. (XXX Perhaps this should use the SDMA port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3775) * instead?) Returns NULL on error, or a struct powerdomain * on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3776) * success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3777) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3778) struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3779) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3780) struct clk *c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3781) struct omap_hwmod_ocp_if *oi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3782) struct clockdomain *clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3783) struct clk_hw_omap *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3784) struct clk_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3786) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3787) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3789) if (oh->clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3790) return oh->clkdm->pwrdm.ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3792) if (oh->_clk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3793) c = oh->_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3794) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3795) oi = _find_mpu_rt_port(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3796) if (!oi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3797) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3798) c = oi->_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3799) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3801) hw = __clk_get_hw(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3802) if (!hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3803) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3805) clk = to_clk_hw_omap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3806) if (!clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3807) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3809) clkdm = clk->clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3810) if (!clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3811) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3813) return clkdm->pwrdm.ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3814) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3816) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3817) * omap_hwmod_get_mpu_rt_va - return the module's base address (for the MPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3818) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3819) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3820) * Returns the virtual address corresponding to the beginning of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3821) * module's register target, in the address range that is intended to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3822) * be used by the MPU. Returns the virtual address upon success or NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3823) * upon error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3824) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3825) void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3826) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3827) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3828) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3830) if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3831) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3833) if (oh->_state == _HWMOD_STATE_UNKNOWN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3834) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3836) return oh->_mpu_rt_va;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3837) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3839) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3840) * XXX what about functions for drivers to save/restore ocp_sysconfig
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3841) * for context save/restore operations?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3842) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3844) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3845) * omap_hwmod_assert_hardreset - assert the HW reset line of submodules
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3846) * contained in the hwmod module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3847) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3848) * @name: name of the reset line to lookup and assert
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3849) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3850) * Some IP like dsp, ipu or iva contain processor that require
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3851) * an HW reset line to be assert / deassert in order to enable fully
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3852) * the IP. Returns -EINVAL if @oh is null or if the operation is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3853) * yet supported on this OMAP; otherwise, passes along the return value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3854) * from _assert_hardreset().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3855) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3856) int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3857) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3858) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3859) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3861) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3862) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3864) spin_lock_irqsave(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3865) ret = _assert_hardreset(oh, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3866) spin_unlock_irqrestore(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3868) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3869) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3871) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3872) * omap_hwmod_deassert_hardreset - deassert the HW reset line of submodules
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3873) * contained in the hwmod module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3874) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3875) * @name: name of the reset line to look up and deassert
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3876) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3877) * Some IP like dsp, ipu or iva contain processor that require
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3878) * an HW reset line to be assert / deassert in order to enable fully
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3879) * the IP. Returns -EINVAL if @oh is null or if the operation is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3880) * yet supported on this OMAP; otherwise, passes along the return value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3881) * from _deassert_hardreset().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3882) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3883) int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3884) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3885) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3886) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3888) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3889) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3891) spin_lock_irqsave(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3892) ret = _deassert_hardreset(oh, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3893) spin_unlock_irqrestore(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3895) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3896) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3898) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3899) * omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3900) * @classname: struct omap_hwmod_class name to search for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3901) * @fn: callback function pointer to call for each hwmod in class @classname
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3902) * @user: arbitrary context data to pass to the callback function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3903) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3904) * For each omap_hwmod of class @classname, call @fn.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3905) * If the callback function returns something other than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3906) * zero, the iterator is terminated, and the callback function's return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3907) * value is passed back to the caller. Returns 0 upon success, -EINVAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3908) * if @classname or @fn are NULL, or passes back the error code from @fn.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3909) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3910) int omap_hwmod_for_each_by_class(const char *classname,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3911) int (*fn)(struct omap_hwmod *oh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3912) void *user),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3913) void *user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3914) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3915) struct omap_hwmod *temp_oh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3916) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3918) if (!classname || !fn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3919) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3921) pr_debug("omap_hwmod: %s: looking for modules of class %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3922) __func__, classname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3924) list_for_each_entry(temp_oh, &omap_hwmod_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3925) if (!strcmp(temp_oh->class->name, classname)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3926) pr_debug("omap_hwmod: %s: %s: calling callback fn\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3927) __func__, temp_oh->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3928) ret = (*fn)(temp_oh, user);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3929) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3930) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3932) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3934) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3935) pr_debug("omap_hwmod: %s: iterator terminated early: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3936) __func__, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3938) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3939) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3941) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3942) * omap_hwmod_set_postsetup_state - set the post-_setup() state for this hwmod
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3943) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3944) * @state: state that _setup() should leave the hwmod in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3945) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3946) * Sets the hwmod state that @oh will enter at the end of _setup()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3947) * (called by omap_hwmod_setup_*()). See also the documentation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3948) * for _setup_postsetup(), above. Returns 0 upon success or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3949) * -EINVAL if there is a problem with the arguments or if the hwmod is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3950) * in the wrong state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3951) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3952) int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3953) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3954) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3955) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3957) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3958) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3960) if (state != _HWMOD_STATE_DISABLED &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3961) state != _HWMOD_STATE_ENABLED &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3962) state != _HWMOD_STATE_IDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3963) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3965) spin_lock_irqsave(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3967) if (oh->_state != _HWMOD_STATE_REGISTERED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3968) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3969) goto ohsps_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3970) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3972) oh->_postsetup_state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3973) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3975) ohsps_unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3976) spin_unlock_irqrestore(&oh->_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3978) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3979) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3981) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3982) * omap_hwmod_get_context_loss_count - get lost context count
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3983) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3984) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3985) * Returns the context loss count of associated @oh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3986) * upon success, or zero if no context loss data is available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3987) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3988) * On OMAP4, this queries the per-hwmod context loss register,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3989) * assuming one exists. If not, or on OMAP2/3, this queries the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3990) * enclosing powerdomain context loss count.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3991) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3992) int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3993) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3994) struct powerdomain *pwrdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3995) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3997) if (soc_ops.get_context_lost)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3998) return soc_ops.get_context_lost(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4000) pwrdm = omap_hwmod_get_pwrdm(oh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4001) if (pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4002) ret = pwrdm_get_context_loss_count(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4004) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4005) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4007) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4008) * omap_hwmod_init - initialize the hwmod code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4009) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4010) * Sets up some function pointers needed by the hwmod code to operate on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4011) * currently-booted SoC. Intended to be called once during kernel init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4012) * before any hwmods are registered. No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4013) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4014) void __init omap_hwmod_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4015) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4016) if (cpu_is_omap24xx()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4017) soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4018) soc_ops.assert_hardreset = _omap2_assert_hardreset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4019) soc_ops.deassert_hardreset = _omap2_deassert_hardreset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4020) soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4021) } else if (cpu_is_omap34xx()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4022) soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4023) soc_ops.assert_hardreset = _omap2_assert_hardreset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4024) soc_ops.deassert_hardreset = _omap2_deassert_hardreset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4025) soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4026) soc_ops.init_clkdm = _init_clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4027) } else if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4028) soc_ops.enable_module = _omap4_enable_module;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4029) soc_ops.disable_module = _omap4_disable_module;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4030) soc_ops.wait_target_ready = _omap4_wait_target_ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4031) soc_ops.assert_hardreset = _omap4_assert_hardreset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4032) soc_ops.deassert_hardreset = _omap4_deassert_hardreset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4033) soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4034) soc_ops.init_clkdm = _init_clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4035) soc_ops.update_context_lost = _omap4_update_context_lost;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4036) soc_ops.get_context_lost = _omap4_get_context_lost;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4037) soc_ops.disable_direct_prcm = _omap4_disable_direct_prcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4038) soc_ops.xlate_clkctrl = _omap4_xlate_clkctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4039) } else if (cpu_is_ti814x() || cpu_is_ti816x() || soc_is_am33xx() ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4040) soc_is_am43xx()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4041) soc_ops.enable_module = _omap4_enable_module;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4042) soc_ops.disable_module = _omap4_disable_module;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4043) soc_ops.wait_target_ready = _omap4_wait_target_ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4044) soc_ops.assert_hardreset = _omap4_assert_hardreset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4045) soc_ops.deassert_hardreset = _am33xx_deassert_hardreset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4046) soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4047) soc_ops.init_clkdm = _init_clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4048) soc_ops.disable_direct_prcm = _omap4_disable_direct_prcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4049) soc_ops.xlate_clkctrl = _omap4_xlate_clkctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4050) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4051) WARN(1, "omap_hwmod: unknown SoC type\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4052) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4053)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4054) _init_clkctrl_providers();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4055)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4056) inited = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4057) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4059) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4060) * omap_hwmod_get_main_clk - get pointer to main clock name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4061) * @oh: struct omap_hwmod *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4062) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4063) * Returns the main clock name assocated with @oh upon success,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4064) * or NULL if @oh is NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4065) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4066) const char *omap_hwmod_get_main_clk(struct omap_hwmod *oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4067) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4068) if (!oh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4069) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4071) return oh->main_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4072) }