From patchwork Tue Nov 16 09:20:20 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Sripathy, Vishwanath" X-Patchwork-Id: 327312 X-Patchwork-Delegate: khilman@deeprootsystems.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oAG9MTwt006074 for ; Tue, 16 Nov 2010 09:22:29 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934085Ab0KPJWJ (ORCPT ); Tue, 16 Nov 2010 04:22:09 -0500 Received: from devils.ext.ti.com ([198.47.26.153]:32912 "EHLO devils.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934081Ab0KPJWF (ORCPT ); Tue, 16 Nov 2010 04:22:05 -0500 Received: from dbdp31.itg.ti.com ([172.24.170.98]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id oAG9M0HG019473 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 16 Nov 2010 03:22:02 -0600 Received: from localhost.localdomain (localhost [127.0.0.1]) by dbdp31.itg.ti.com (8.13.8/8.13.8) with ESMTP id oAG9LvkK028974; Tue, 16 Nov 2010 14:51:58 +0530 (IST) From: Vishwanath BS To: linux-omap@vger.kernel.org Cc: Vishwanath BS , Kevin Hilman , Paul Walmsley Subject: [PATCHv2]OMAP PM:MPU/DMA Latency constraints Date: Tue, 16 Nov 2010 14:50:20 +0530 Message-Id: <1289899220-23003-1-git-send-email-vishwanath.bs@ti.com> X-Mailer: git-send-email 1.7.0.4 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 16 Nov 2010 09:22:29 +0000 (UTC) diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 92c5bb7..4ff485e 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -184,6 +184,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 3f0a2bb..545a6a1 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -38,3 +38,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 a5bff9c..eb9a7cb 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -114,7 +114,8 @@ static inline int omap1_i2c_add_bus(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); + static struct pm_qos_request_list *qos_handle; + omap_pm_set_max_mpu_wakeup_lat(&qos_handle, t); } static struct omap_device_pm_latency omap_i2c_latency[] = { diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h index c5b533d..6425e82 --- a/arch/arm/plat-omap/include/plat/omap-pm.h +++ b/arch/arm/plat-omap/include/plat/omap-pm.h @@ -20,6 +20,7 @@ #include "powerdomain.h" #include +#include /* * agent_id values for use with omap_pm_set_min_bus_tput(): @@ -75,7 +76,8 @@ 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 @@ -107,7 +109,8 @@ 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); /** @@ -174,7 +177,8 @@ 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 @@ -199,7 +203,8 @@ 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 ca75abb..abcf9ae --- a/arch/arm/plat-omap/omap-pm-noop.c +++ b/arch/arm/plat-omap/omap-pm-noop.c @@ -30,19 +30,19 @@ * 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); + "t = %ld usec\n", t); /* * For current Linux, this needs to map the MPU to a @@ -116,19 +116,19 @@ 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); + "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..9002334 --- /dev/null +++ b/arch/arm/plat-omap/omap-pm.c @@ -0,0 +1,316 @@ +/* + * 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 +#include +#include +#include + +/* Interface documentation is in mach/omap-pm.h */ +#include + +#include + +/* + * 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("OMAP PM: %s: invalid parameter(s)\n", __func__); + return -EINVAL; + }; + + if (t == -1) { + pm_qos_remove_request(*qos_request); + kfree(*qos_request); + *qos_request = NULL; + } else if (*qos_request == NULL) { + *qos_request = kzalloc(sizeof(struct pm_qos_request_list), + GFP_KERNEL); + if (!*qos_request) { + pr_warning("OMAP PM: %s: kzalloc failed\n", __func__); + return -ENOMEM; + } + pm_qos_add_request(*qos_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("OMAP PM: %s: invalid parameter(s)\n", __func__); + return -EINVAL; + }; + + if (t == -1) { + pm_qos_remove_request(*qos_request); + kfree(*qos_request); + *qos_request = NULL; + } else if (*qos_request == NULL) { + *qos_request = kzalloc(sizeof(struct pm_qos_request_list), + GFP_KERNEL); + if (!*qos_request) { + pr_warning("OMAP PM: %s: kzalloc failed\n", __func__); + return -ENOMEM; + } + pm_qos_add_request(*qos_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(void) + +{ + 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 */ +} + +