2021-02-04 03:59:36

by Lubomir Rintel

[permalink] [raw]
Subject: [PATCH 1/1] clk: mmp2: Enable the 3D GPU clock alongside the 2D clock

The bits intended to control the 3D GPU clock need to be enabled for the
2D GPU to work. It is not clear why this needs to be done.

Forcing the 3D clock on when the etnaviv driver requests a 2D clock
works around the problem.

Signed-off-by: Lubomir Rintel <[email protected]>
---
drivers/clk/mmp/clk-gate.c | 9 ++++++++-
drivers/clk/mmp/clk-of-mmp2.c | 2 +-
drivers/clk/mmp/clk.c | 3 ++-
drivers/clk/mmp/clk.h | 10 +++++++++-
4 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/mmp/clk-gate.c b/drivers/clk/mmp/clk-gate.c
index 1755916ddef2d..bf93ffb258667 100644
--- a/drivers/clk/mmp/clk-gate.c
+++ b/drivers/clk/mmp/clk-gate.c
@@ -9,6 +9,7 @@
* warranty of any kind, whether express or implied.
*/

+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/io.h>
@@ -31,6 +32,8 @@ static int mmp_clk_gate_enable(struct clk_hw *hw)
unsigned long rate;
u32 tmp;

+ clk_prepare_enable(gate->companion);
+
if (gate->lock)
spin_lock_irqsave(gate->lock, flags);

@@ -67,6 +70,8 @@ static void mmp_clk_gate_disable(struct clk_hw *hw)

if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
+
+ clk_disable_unprepare(gate->companion);
}

static int mmp_clk_gate_is_enabled(struct clk_hw *hw)
@@ -95,7 +100,8 @@ const struct clk_ops mmp_clk_gate_ops = {
struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable,
- unsigned int gate_flags, spinlock_t *lock)
+ unsigned int gate_flags, spinlock_t *lock,
+ struct clk *companion)
{
struct mmp_clk_gate *gate;
struct clk *clk;
@@ -119,6 +125,7 @@ struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
gate->val_disable = val_disable;
gate->flags = gate_flags;
gate->lock = lock;
+ gate->companion = companion;
gate->hw.init = &init;

clk = clk_register(dev, &gate->hw);
diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c
index 8b2eb989980bf..7ac96a1dcd60c 100644
--- a/drivers/clk/mmp/clk-of-mmp2.c
+++ b/drivers/clk/mmp/clk-of-mmp2.c
@@ -394,7 +394,7 @@ static struct mmp_param_gate_clk mmp2_apmu_gate_clks[] = {
static struct mmp_param_gate_clk mmp3_apmu_gate_clks[] = {
{MMP3_CLK_SDH4, "sdh4_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH4, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP3_CLK_GPU_3D, "gpu_3d_clk", "gpu_3d_div", CLK_SET_RATE_PARENT, APMU_GPU, 0x5, 0x5, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock},
- {MMP3_CLK_GPU_2D, "gpu_2d_clk", "gpu_2d_div", CLK_SET_RATE_PARENT, APMU_GPU, 0x1c0000, 0x1c0000, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock},
+ {MMP3_CLK_GPU_2D, "gpu_2d_clk", "gpu_2d_div", CLK_SET_RATE_PARENT, APMU_GPU, 0x1c0000, 0x1c0000, 0x0, MMP_CLK_GATE_NEED_DELAY, &gpu_lock, MMP3_CLK_GPU_3D},
};

static void mmp2_axi_periph_clk_init(struct mmp2_clk_unit *pxa_unit)
diff --git a/drivers/clk/mmp/clk.c b/drivers/clk/mmp/clk.c
index ca7d37e2c7be6..05d2b901cae5f 100644
--- a/drivers/clk/mmp/clk.c
+++ b/drivers/clk/mmp/clk.c
@@ -109,7 +109,8 @@ void mmp_register_gate_clks(struct mmp_clk_unit *unit,
clks[i].val_enable,
clks[i].val_disable,
clks[i].gate_flags,
- clks[i].lock);
+ clks[i].lock,
+ unit->clk_table[clks[i].companion_id]);

if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index 55ac053797819..385b74e671c31 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -117,6 +117,13 @@ struct mmp_clk_gate {
u32 val_disable;
unsigned int flags;
spinlock_t *lock;
+
+ /*
+ * The sole purpose of this is to make sure the 3D GPU clock gets
+ * enabled alongside 2D GPU clock, otherwise the 2D unit wouldn't
+ * work. It is not know why this needs to be done.
+ */
+ struct clk *companion;
};

extern const struct clk_ops mmp_clk_gate_ops;
@@ -124,7 +131,7 @@ extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u32 mask, u32 val_enable,
u32 val_disable, unsigned int gate_flags,
- spinlock_t *lock);
+ spinlock_t *lock, struct clk *companion);

extern struct clk *mmp_clk_register_apbc(const char *name,
const char *parent_name, void __iomem *base,
@@ -187,6 +194,7 @@ struct mmp_param_gate_clk {
u32 val_disable;
unsigned int gate_flags;
spinlock_t *lock;
+ unsigned int companion_id;
};
void mmp_register_gate_clks(struct mmp_clk_unit *unit,
struct mmp_param_gate_clk *clks,
--
2.29.2