|
@@ -461,3 +461,173 @@ static void aurora_pa_range(unsigned long start, unsigned long end,
|
|
|
|
|
|
raw_spin_lock_irqsave(&l2x0_lock, flags);
|
|
|
writel_relaxed(start, l2x0_base + AURORA_RANGE_BASE_ADDR_REG);
|
|
|
+ writel_relaxed(end, l2x0_base + offset);
|
|
|
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
|
|
|
+
|
|
|
+ cache_sync();
|
|
|
+}
|
|
|
+
|
|
|
+static void aurora_inv_range(unsigned long start, unsigned long end)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * round start and end adresses up to cache line size
|
|
|
+ */
|
|
|
+ start &= ~(CACHE_LINE_SIZE - 1);
|
|
|
+ end = ALIGN(end, CACHE_LINE_SIZE);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Invalidate all full cache lines between 'start' and 'end'.
|
|
|
+ */
|
|
|
+ while (start < end) {
|
|
|
+ unsigned long range_end = calc_range_end(start, end);
|
|
|
+ aurora_pa_range(start, range_end - CACHE_LINE_SIZE,
|
|
|
+ AURORA_INVAL_RANGE_REG);
|
|
|
+ start = range_end;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void aurora_clean_range(unsigned long start, unsigned long end)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * If L2 is forced to WT, the L2 will always be clean and we
|
|
|
+ * don't need to do anything here.
|
|
|
+ */
|
|
|
+ if (!l2_wt_override) {
|
|
|
+ start &= ~(CACHE_LINE_SIZE - 1);
|
|
|
+ end = ALIGN(end, CACHE_LINE_SIZE);
|
|
|
+ while (start != end) {
|
|
|
+ unsigned long range_end = calc_range_end(start, end);
|
|
|
+ aurora_pa_range(start, range_end - CACHE_LINE_SIZE,
|
|
|
+ AURORA_CLEAN_RANGE_REG);
|
|
|
+ start = range_end;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void aurora_flush_range(unsigned long start, unsigned long end)
|
|
|
+{
|
|
|
+ start &= ~(CACHE_LINE_SIZE - 1);
|
|
|
+ end = ALIGN(end, CACHE_LINE_SIZE);
|
|
|
+ while (start != end) {
|
|
|
+ unsigned long range_end = calc_range_end(start, end);
|
|
|
+ /*
|
|
|
+ * If L2 is forced to WT, the L2 will always be clean and we
|
|
|
+ * just need to invalidate.
|
|
|
+ */
|
|
|
+ if (l2_wt_override)
|
|
|
+ aurora_pa_range(start, range_end - CACHE_LINE_SIZE,
|
|
|
+ AURORA_INVAL_RANGE_REG);
|
|
|
+ else
|
|
|
+ aurora_pa_range(start, range_end - CACHE_LINE_SIZE,
|
|
|
+ AURORA_FLUSH_RANGE_REG);
|
|
|
+ start = range_end;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void __init l2x0_of_setup(const struct device_node *np,
|
|
|
+ u32 *aux_val, u32 *aux_mask)
|
|
|
+{
|
|
|
+ u32 data[2] = { 0, 0 };
|
|
|
+ u32 tag = 0;
|
|
|
+ u32 dirty = 0;
|
|
|
+ u32 val = 0, mask = 0;
|
|
|
+
|
|
|
+ of_property_read_u32(np, "arm,tag-latency", &tag);
|
|
|
+ if (tag) {
|
|
|
+ mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK;
|
|
|
+ val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT;
|
|
|
+ }
|
|
|
+
|
|
|
+ of_property_read_u32_array(np, "arm,data-latency",
|
|
|
+ data, ARRAY_SIZE(data));
|
|
|
+ if (data[0] && data[1]) {
|
|
|
+ mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK |
|
|
|
+ L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK;
|
|
|
+ val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) |
|
|
|
+ ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT);
|
|
|
+ }
|
|
|
+
|
|
|
+ of_property_read_u32(np, "arm,dirty-latency", &dirty);
|
|
|
+ if (dirty) {
|
|
|
+ mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK;
|
|
|
+ val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
|
|
|
+ }
|
|
|
+
|
|
|
+ *aux_val &= ~mask;
|
|
|
+ *aux_val |= val;
|
|
|
+ *aux_mask &= ~mask;
|
|
|
+}
|
|
|
+
|
|
|
+static void __init pl310_of_setup(const struct device_node *np,
|
|
|
+ u32 *aux_val, u32 *aux_mask)
|
|
|
+{
|
|
|
+ u32 data[3] = { 0, 0, 0 };
|
|
|
+ u32 tag[3] = { 0, 0, 0 };
|
|
|
+ u32 filter[2] = { 0, 0 };
|
|
|
+
|
|
|
+ of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
|
|
|
+ if (tag[0] && tag[1] && tag[2])
|
|
|
+ writel_relaxed(
|
|
|
+ ((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
|
|
|
+ ((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
|
|
|
+ ((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
|
|
|
+ l2x0_base + L2X0_TAG_LATENCY_CTRL);
|
|
|
+
|
|
|
+ of_property_read_u32_array(np, "arm,data-latency",
|
|
|
+ data, ARRAY_SIZE(data));
|
|
|
+ if (data[0] && data[1] && data[2])
|
|
|
+ writel_relaxed(
|
|
|
+ ((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
|
|
|
+ ((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
|
|
|
+ ((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
|
|
|
+ l2x0_base + L2X0_DATA_LATENCY_CTRL);
|
|
|
+
|
|
|
+ of_property_read_u32_array(np, "arm,filter-ranges",
|
|
|
+ filter, ARRAY_SIZE(filter));
|
|
|
+ if (filter[1]) {
|
|
|
+ writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M),
|
|
|
+ l2x0_base + L2X0_ADDR_FILTER_END);
|
|
|
+ writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN,
|
|
|
+ l2x0_base + L2X0_ADDR_FILTER_START);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void __init pl310_save(void)
|
|
|
+{
|
|
|
+ u32 l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
|
|
|
+ L2X0_CACHE_ID_RTL_MASK;
|
|
|
+
|
|
|
+ l2x0_saved_regs.tag_latency = readl_relaxed(l2x0_base +
|
|
|
+ L2X0_TAG_LATENCY_CTRL);
|
|
|
+ l2x0_saved_regs.data_latency = readl_relaxed(l2x0_base +
|
|
|
+ L2X0_DATA_LATENCY_CTRL);
|
|
|
+ l2x0_saved_regs.filter_end = readl_relaxed(l2x0_base +
|
|
|
+ L2X0_ADDR_FILTER_END);
|
|
|
+ l2x0_saved_regs.filter_start = readl_relaxed(l2x0_base +
|
|
|
+ L2X0_ADDR_FILTER_START);
|
|
|
+
|
|
|
+ if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) {
|
|
|
+ /*
|
|
|
+ * From r2p0, there is Prefetch offset/control register
|
|
|
+ */
|
|
|
+ l2x0_saved_regs.prefetch_ctrl = readl_relaxed(l2x0_base +
|
|
|
+ L2X0_PREFETCH_CTRL);
|
|
|
+ /*
|
|
|
+ * From r3p0, there is Power control register
|
|
|
+ */
|
|
|
+ if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0)
|
|
|
+ l2x0_saved_regs.pwr_ctrl = readl_relaxed(l2x0_base +
|
|
|
+ L2X0_POWER_CTRL);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void aurora_save(void)
|
|
|
+{
|
|
|
+ l2x0_saved_regs.ctrl = readl_relaxed(l2x0_base + L2X0_CTRL);
|
|
|
+ l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
|
|
|
+}
|
|
|
+
|
|
|
+static void l2x0_resume(void)
|
|
|
+{
|
|
|
+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
|
|
|
+ /* restore aux ctrl and enable l2 */
|