@@ -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);
@@ -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)
@@ -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",
@@ -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,
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 <lkundrak@v3.sk> --- 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(-)