Signed-off-by: Yong Zhi
---
drivers/media/pci/intel/ipu3/ipu3-css.c | 515
drivers/media/pci/intel/ipu3/ipu3-css.h | 5 +
2 files changed, 520 insertions(+)
create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css.c
diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.c
b/drivers/media/pci/intel/ipu3/ipu3-css.c
new file mode 100644
index 000..675be91
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-css.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include
+#include
+#include "ipu3-css.h"
+#include "ipu3-css-fw.h"
+#include "ipu3-tables.h"
+
+/* IRQ configuration */
+#define IMGU_IRQCTRL_IRQ_MASK (IMGU_IRQCTRL_IRQ_SP1 | \
+IMGU_IRQCTRL_IRQ_SP2 | \
+IMGU_IRQCTRL_IRQ_SW_PIN(0) | \
+IMGU_IRQCTRL_IRQ_SW_PIN(1))
+
+static void writes(void *mem, ssize_t len, void __iomem *reg)
+{
+ while (len >= 4) {
+ writel(*(u32 *)mem, reg);
+ mem += 4;
+ reg += 4;
+ len -= 4;
+ }
+}
+
+/*** css hw ***/
+
+/* Wait until register `reg', masked with `mask', becomes `cmp' */
+static int ipu3_css_hw_wait(struct ipu3_css *css, int reg, u32 mask, u32 cmp)
+{
+ static const unsigned int delay = 1000;
+ unsigned int maxloops = 100 / 10 / delay;
+
+ do {
+ if ((readl(css->base + reg) & mask) == cmp)
+ return 0;
+ usleep_range(delay, 2 * delay);
+ } while (--maxloops);
+
+ return -EIO;
+}
+
+/* Initialize the IPU3 CSS hardware and associated h/w blocks */
+
+int ipu3_css_set_powerup(struct ipu3_css *css)
+{
+ struct device *dev = css->dev;
+ void __iomem *const base = css->base;
+ u32 pm_ctrl, state;
+
+ /* Clear the CSS busy signal */
+ readl(base + IMGU_REG_GP_BUSY);
+ writel(0, base + IMGU_REG_GP_BUSY);
+
+ /* Wait for idle signal */
+ if (ipu3_css_hw_wait(css, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
+ IMGU_STATE_IDLE_STS))
+ dev_warn(dev, "failed to set CSS idle\n");
+
+ /* Reset the css */
+ writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_RESET,
+ base + IMGU_REG_PM_CTRL);
+
+ usleep_range(200, 300);
+
+ /** Prepare CSS */
+
+ pm_ctrl = readl(base + IMGU_REG_PM_CTRL);
+ state = readl(base + IMGU_REG_STATE);
+
+ dev_dbg(dev, "CSS pm_ctrl 0x%x state 0x%x (power %s)\n",
+ pm_ctrl, state, state & IMGU_STATE_POWER_DOWN ? "down" : "up");
+
+ /* Power up CSS using wrapper */
+ if (state & IMGU_STATE_POWER_DOWN) {
+ writel(IMGU_PM_CTRL_RACE_TO_HALT | IMGU_PM_CTRL_START,
+ base + IMGU_REG_PM_CTRL);
+ if (ipu3_css_hw_wait(css, IMGU_REG_PM_CTRL,
+ IMGU_PM_CTRL_START, 0))
+ dev_warn(dev, "failed to power up CSS\n");
+ usleep_range(2000, 3000);
+ } else {
+ writel(IMGU_PM_CTRL_RACE_TO_HALT, base + IMGU_REG_PM_CTRL);
+ }
+
+ /* Set the busy bit */
+ writel(readl(base + IMGU_REG_GP_BUSY) | 1, base + IMGU_REG_GP_BUSY);
+
+ return 0;
+}
+
+int ipu3_css_set_powerdown(struct ipu3_css *css)
+{
+ struct device *dev = css->dev;
+ void __iomem *const base = css->base;
+
+ /* Clear the CSS busy signal */
+ readl(base + IMGU_REG_GP_BUSY);
+ writel(0, base + IMGU_REG_GP_BUSY);
+
+ /* Wait for idle signal */
+ if (ipu3_css_hw_wait(css, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
+ IMGU_STATE_IDLE_STS))
+ dev_warn(dev, "failed to set CSS idle\n");
+
+ /* Reset the css */
+ writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_CSS_PWRDN,
+ base + IMGU_REG_PM_CTRL);
+
+ return 0;
+}
+
+static int ipu3_css_hw_init(struct ipu3_css *css)
+{
+ /* For checking that streaming monitor statuses are valid */
+ static const struct {
+ u32 reg;
+ u32 mask;
+ const char *name;
+ } stream_monitors[] = {
+ {
+ IMGU_REG_GP_SP1_STRMON_STAT,
+ IMGU_GP_STRMON_STAT_ISP_PORT_SP12ISP,
+ "ISP0 to SP0"
+ }, {
+