#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
#include <linux/sort.h>
#include <linux/types.h>
struct tegra_emc {
struct device *dev;
struct completion clk_handshake_complete;
+ struct notifier_block qos_nb;
struct notifier_block clk_nb;
struct clk *backup_clk;
struct clk *emc_mux;
return notifier_from_errno(err);
}
+static int tegra_emc_qos_request_notify(struct notifier_block *nb,
+ unsigned long memory_bandwidth,
+ void *data)
+{
+ struct tegra_emc *emc = container_of(nb, struct tegra_emc, qos_nb);
+ unsigned long long max_rate;
+ unsigned long long rate;
+ int err;
+
+ /* get maximum possible rate */
+ max_rate = emc->timings[emc->num_timings - 1].rate;
+
+ /* DDR: 8 bytes per clock, 1 Mbit/s: 125000 B/s, EMC: 2x BUS rate */
+ rate = memory_bandwidth * 125000 / 8 * 2;
+
+ /* clamp rate to maximum possible */
+ rate = min(rate, max_rate);
+
+ /* update EMC clock rate */
+ err = clk_set_rate(emc->clk, rate);
+
+ return notifier_from_errno(err);
+}
+
static int load_one_timing_from_dt(struct tegra_emc *emc,
struct emc_timing *timing,
struct device_node *node)
init_completion(&emc->clk_handshake_complete);
emc->clk_nb.notifier_call = tegra_emc_clk_change_notify;
+ emc->qos_nb.notifier_call = tegra_emc_qos_request_notify;
emc->dev = &pdev->dev;
err = tegra_emc_load_timings_from_dt(emc, np);
if (err) {
dev_err(&pdev->dev, "failed to initialize EMC clock rate: %d\n",
err);
- goto unreg_notifier;
+ goto unreg_clk_notifier;
+ }
+
+ err = pm_qos_add_notifier(PM_QOS_MEMORY_BANDWIDTH, &emc->qos_nb);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register QoS notifier: %d\n",
+ err);
+ goto unreg_clk_notifier;
}
return 0;
-unreg_notifier:
+unreg_clk_notifier:
clk_notifier_unregister(emc->clk, &emc->clk_nb);
put_backup:
clk_put(emc->backup_clk);