This patch has implementation for OMAP MPU/DMA Latency constraints using PM QOS. Signed-off-by: Vishwanath Sripathy <vishwanath.bs@xxxxxx> --- arch/arm/plat-omap/Kconfig | 3 + arch/arm/plat-omap/Makefile | 1 + arch/arm/plat-omap/i2c.c | 3 +- arch/arm/plat-omap/include/plat/omap-pm.h | 9 +- arch/arm/plat-omap/omap-pm-noop.c | 20 +-- arch/arm/plat-omap/omap-pm.c | 309 +++++++++++++++++++++++++++++ 6 files changed, 328 insertions(+), 17 deletions(-) create mode 100755 arch/arm/plat-omap/omap-pm.c diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 286b606..ce544b0 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -194,6 +194,9 @@ config OMAP_PM_NONE config OMAP_PM_NOOP bool "No-op/debug PM layer" +config OMAP_PM + depends on PM + bool "OMAP PM layer implementation" endchoice endmenu diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 2a15191..fad2475 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -32,3 +32,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y) obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o +obj-$(CONFIG_OMAP_PM) += omap-pm.o diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index a5ce4f0..29dc45a --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -145,7 +145,8 @@ static inline int omap1_i2c_add_bus(struct platform_device *pdev, int bus_id) */ static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t) { - omap_pm_set_max_mpu_wakeup_lat(dev, t); + struct pm_qos_request_list *qos_handle = NULL; + omap_pm_set_max_mpu_wakeup_lat(&qos_handle, t); } static inline int omap2_i2c_add_bus(struct platform_device *pdev, int bus_id) diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h index 728fbb9..47ba9e6 100644 --- a/arch/arm/plat-omap/include/plat/omap-pm.h +++ b/arch/arm/plat-omap/include/plat/omap-pm.h @@ -19,6 +19,7 @@ #include <linux/clk.h> #include "powerdomain.h" +#include <linux/pm_qos_params.h> /** * struct omap_opp - clock frequency-to-OPP ID table for DSP, MPU @@ -86,7 +87,7 @@ void omap_pm_if_exit(void); /** * omap_pm_set_max_mpu_wakeup_lat - set the maximum MPU wakeup latency - * @dev: struct device * requesting the constraint + * @qos_request: handle for the constraint. The pointer should be initialized to NULL * @t: maximum MPU wakeup latency in microseconds * * Request that the maximum interrupt latency for the MPU to be no @@ -118,7 +119,7 @@ void omap_pm_if_exit(void); * Returns -EINVAL for an invalid argument, -ERANGE if the constraint * is not satisfiable, or 0 upon success. */ -int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t); +int omap_pm_set_max_mpu_wakeup_lat(struct pm_qos_request_list **qos_request, long t); /** @@ -185,7 +186,7 @@ int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev, /** * omap_pm_set_max_sdma_lat - set the maximum system DMA transfer start latency - * @dev: struct device * + * @qos_request: handle for the constraint. The pointer should be initialized to NULL * @t: maximum DMA transfer start latency in microseconds * * Request that the maximum system DMA transfer start latency for this @@ -210,7 +211,7 @@ int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev, * Returns -EINVAL for an invalid argument, -ERANGE if the constraint * is not satisfiable, or 0 upon success. */ -int omap_pm_set_max_sdma_lat(struct device *dev, long t); +int omap_pm_set_max_sdma_lat(struct pm_qos_request_list **qos_request, long t); /** diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c index e129ce8..af2fe43 100644 --- a/arch/arm/plat-omap/omap-pm-noop.c +++ b/arch/arm/plat-omap/omap-pm-noop.c @@ -34,19 +34,17 @@ struct omap_opp *l3_opps; * Device-driver-originated constraints (via board-*.c files) */ -int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t) +int omap_pm_set_max_mpu_wakeup_lat(struct pm_qos_request_list **pmqos_req, long t) { - if (!dev || t < -1) { + if (!pmqos_req || t < -1) { WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); return -EINVAL; }; if (t == -1) - pr_debug("OMAP PM: remove max MPU wakeup latency constraint: " - "dev %s\n", dev_name(dev)); + pr_debug("OMAP PM: remove max MPU wakeup latency constraint\n"); else - pr_debug("OMAP PM: add max MPU wakeup latency constraint: " - "dev %s, t = %ld usec\n", dev_name(dev), t); + pr_debug("OMAP PM: add max MPU wakeup latency constraint: t = %ld usec\n", t); /* * For current Linux, this needs to map the MPU to a @@ -120,19 +118,17 @@ int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev, return 0; } -int omap_pm_set_max_sdma_lat(struct device *dev, long t) +int omap_pm_set_max_sdma_lat(struct pm_qos_request_list **qos_request, long t) { - if (!dev || t < -1) { + if (!qos_request || t < -1) { WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); return -EINVAL; }; if (t == -1) - pr_debug("OMAP PM: remove max DMA latency constraint: " - "dev %s\n", dev_name(dev)); + pr_debug("OMAP PM: remove max DMA latency constraint:\n"); else - pr_debug("OMAP PM: add max DMA latency constraint: " - "dev %s, t = %ld usec\n", dev_name(dev), t); + pr_debug("OMAP PM: add max DMA latency constraint: t = %ld usec\n", t); /* * For current Linux PM QOS params, this code should scan the diff --git a/arch/arm/plat-omap/omap-pm.c b/arch/arm/plat-omap/omap-pm.c new file mode 100755 index 0000000..937196a --- /dev/null +++ b/arch/arm/plat-omap/omap-pm.c @@ -0,0 +1,309 @@ +/* + * omap-pm.c - OMAP power management interface + * + * Copyright (C) 2008-2010 Texas Instruments, Inc. + * Copyright (C) 2008-2009 Nokia Corporation + * Vishwanath BS + * + * This code is based on plat-omap/omap-pm-noop.c. + * + * Interface developed by (in alphabetical order): + * Karthik Dasu, Tony Lindgren, Rajendra Nayak, Sakari Poussa, Veeramanikandan + * Raju, Anand Sawant, Igor Stoppa, Paul Walmsley, Richard Woodruff + */ + +#undef DEBUG + +#include <linux/init.h> +#include <linux/cpufreq.h> +#include <linux/device.h> + +/* Interface documentation is in mach/omap-pm.h */ +#include <plat/omap-pm.h> + +#include <plat/powerdomain.h> + +struct omap_opp *dsp_opps; +struct omap_opp *mpu_opps; +struct omap_opp *l3_opps; + +/* + * Device-driver-originated constraints (via board-*.c files) + */ + +int omap_pm_set_max_mpu_wakeup_lat(struct pm_qos_request_list **qos_request, long t) +{ + if (!qos_request || t < -1) { + pr_warning("Warning: invalid params to omap_pm_set_max_mpu_wakeup_lat \n:"); + return -EINVAL; + }; + + if (t == -1) { + pm_qos_remove_request(*qos_request); + *qos_request = NULL; + } else if (*qos_request == NULL) + *qos_request = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY, t); + else + pm_qos_update_request(*qos_request, t); + + return 0; +} + + +int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r) +{ + if (!dev || (agent_id != OCP_INITIATOR_AGENT && + agent_id != OCP_TARGET_AGENT)) { + WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); + return -EINVAL; + }; + + if (r == 0) + pr_debug("OMAP PM: remove min bus tput constraint: " + "dev %s for agent_id %d\n", dev_name(dev), agent_id); + else + pr_debug("OMAP PM: add min bus tput constraint: " + "dev %s for agent_id %d: rate %ld KiB\n", + dev_name(dev), agent_id, r); + + /* + * This code should model the interconnect and compute the + * required clock frequency, convert that to a VDD2 OPP ID, then + * set the VDD2 OPP appropriately. + * + * TI CDP code can call constraint_set here on the VDD2 OPP. + */ + + return 0; +} + +int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev, + long t) +{ + if (!req_dev || !dev || t < -1) { + WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); + return -EINVAL; + }; + + if (t == -1) + pr_debug("OMAP PM: remove max device latency constraint: " + "dev %s\n", dev_name(dev)); + else + pr_debug("OMAP PM: add max device latency constraint: " + "dev %s, t = %ld usec\n", dev_name(dev), t); + + /* + * For current Linux, this needs to map the device to a + * powerdomain, then go through the list of current max lat + * constraints on that powerdomain and find the smallest. If + * the latency constraint has changed, the code should + * recompute the state to enter for the next powerdomain + * state. Conceivably, this code should also determine + * whether to actually disable the device clocks or not, + * depending on how long it takes to re-enable the clocks. + * + * TI CDP code can call constraint_set here. + */ + + return 0; +} + +int omap_pm_set_max_sdma_lat(struct pm_qos_request_list **qos_request, long t) +{ + if (!qos_request || t < -1) { + pr_warning("Warning: invalid params to omap_pm_set_max_sdma_lat\n:"); + return -EINVAL; + }; + + if (t == -1) { + pm_qos_remove_request(*qos_request); + *qos_request = NULL; + } else if (*qos_request == NULL) + *qos_request = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY, t); + else + pm_qos_update_request(*qos_request, t); + + return 0; +} + +int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r) +{ + if (!dev || !c || r < 0) { + WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); + return -EINVAL; + } + + if (r == 0) + pr_debug("OMAP PM: remove min clk rate constraint: " + "dev %s\n", dev_name(dev)); + else + pr_debug("OMAP PM: add min clk rate constraint: " + "dev %s, rate = %ld Hz\n", dev_name(dev), r); + + /* + * Code in a real implementation should keep track of these + * constraints on the clock, and determine the highest minimum + * clock rate. It should iterate over each OPP and determine + * whether the OPP will result in a clock rate that would + * satisfy this constraint (and any other PM constraint in effect + * at that time). Once it finds the lowest-voltage OPP that + * meets those conditions, it should switch to it, or return + * an error if the code is not capable of doing so. + */ + + return 0; +} + +/* + * DSP Bridge-specific constraints + */ + +const struct omap_opp *omap_pm_dsp_get_opp_table(void) +{ + pr_debug("OMAP PM: DSP request for OPP table\n"); + + /* + * Return DSP frequency table here: The final item in the + * array should have .rate = .opp_id = 0. + */ + + return NULL; +} + +void omap_pm_dsp_set_min_opp(u8 opp_id) +{ + if (opp_id == 0) { + WARN_ON(1); + return; + } + + pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id); + + /* + * + * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we + * can just test to see which is higher, the CPU's desired OPP + * ID or the DSP's desired OPP ID, and use whichever is + * highest. + * + * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP + * rate is keyed on MPU speed, not the OPP ID. So we need to + * map the OPP ID to the MPU speed for use with clk_set_rate() + * if it is higher than the current OPP clock rate. + * + */ +} + + +u8 omap_pm_dsp_get_opp(void) +{ + pr_debug("OMAP PM: DSP requests current DSP OPP ID\n"); + + /* + * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock + * + * CDP12.14+: + * Call clk_get_rate() on the OPP custom clock, map that to an + * OPP ID using the tables defined in board-*.c/chip-*.c files. + */ + + return 0; +} + +/* + * CPUFreq-originated constraint + * + * In the future, this should be handled by custom OPP clocktype + * functions. + */ + +struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void) +{ + pr_debug("OMAP PM: CPUFreq request for frequency table\n"); + + /* + * Return CPUFreq frequency table here: loop over + * all VDD1 clkrates, pull out the mpu_ck frequencies, build + * table + */ + + return NULL; +} + +void omap_pm_cpu_set_freq(unsigned long f) +{ + if (f == 0) { + WARN_ON(1); + return; + } + + pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n", + f); + + /* + * For l-o dev tree, determine whether MPU freq or DSP OPP id + * freq is higher. Find the OPP ID corresponding to the + * higher frequency. Call clk_round_rate() and clk_set_rate() + * on the OPP custom clock. + * + * CDP should just be able to set the VDD1 OPP clock rate here. + */ +} + +unsigned long omap_pm_cpu_get_freq(void) +{ + pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n"); + + /* + * Call clk_get_rate() on the mpu_ck. + */ + + return 0; +} + +/* + * Device context loss tracking + */ + +int omap_pm_get_dev_context_loss_count(struct device *dev) +{ + if (!dev) { + WARN_ON(1); + return -EINVAL; + }; + + pr_debug("OMAP PM: returning context loss count for dev %s\n", + dev_name(dev)); + + /* + * Map the device to the powerdomain. Return the powerdomain + * off counter. + */ + + return 0; +} + + +/* Should be called before clk framework init */ +int __init omap_pm_if_early_init(struct omap_opp *mpu_opp_table, + struct omap_opp *dsp_opp_table, + struct omap_opp *l3_opp_table) +{ + mpu_opps = mpu_opp_table; + dsp_opps = dsp_opp_table; + l3_opps = l3_opp_table; + return 0; +} + +/* Must be called after clock framework is initialized */ +int __init omap_pm_if_init(void) +{ + return 0; +} + +void omap_pm_if_exit(void) +{ + /* Deallocate CPUFreq frequency table here */ +} + + -- 1.5.4.7 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html