crypto: talitos - adapt interrupts and reset functions to SEC1
[firefly-linux-kernel-4.4.55.git] / drivers / crypto / talitos.c
index 6d77699a821b49f54d813346ac9ae97acbf47ed7..12654056ca53bd8e41a347e300337793404a961d 100644 (file)
@@ -124,12 +124,23 @@ static int reset_channel(struct device *dev, int ch)
 {
        struct talitos_private *priv = dev_get_drvdata(dev);
        unsigned int timeout = TALITOS_TIMEOUT;
+       bool is_sec1 = has_ftr_sec1(priv);
 
-       setbits32(priv->chan[ch].reg + TALITOS_CCCR, TALITOS_CCCR_RESET);
+       if (is_sec1) {
+               setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO,
+                         TALITOS1_CCCR_LO_RESET);
 
-       while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) & TALITOS_CCCR_RESET)
-              && --timeout)
-               cpu_relax();
+               while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR_LO) &
+                       TALITOS1_CCCR_LO_RESET) && --timeout)
+                       cpu_relax();
+       } else {
+               setbits32(priv->chan[ch].reg + TALITOS_CCCR,
+                         TALITOS2_CCCR_RESET);
+
+               while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) &
+                       TALITOS2_CCCR_RESET) && --timeout)
+                       cpu_relax();
+       }
 
        if (timeout == 0) {
                dev_err(dev, "failed to reset channel %d\n", ch);
@@ -152,11 +163,12 @@ static int reset_device(struct device *dev)
 {
        struct talitos_private *priv = dev_get_drvdata(dev);
        unsigned int timeout = TALITOS_TIMEOUT;
-       u32 mcr = TALITOS_MCR_SWR;
+       bool is_sec1 = has_ftr_sec1(priv);
+       u32 mcr = is_sec1 ? TALITOS1_MCR_SWR : TALITOS2_MCR_SWR;
 
        setbits32(priv->reg + TALITOS_MCR, mcr);
 
-       while ((in_be32(priv->reg + TALITOS_MCR) & TALITOS_MCR_SWR)
+       while ((in_be32(priv->reg + TALITOS_MCR) & mcr)
               && --timeout)
                cpu_relax();
 
@@ -180,6 +192,7 @@ static int init_device(struct device *dev)
 {
        struct talitos_private *priv = dev_get_drvdata(dev);
        int ch, err;
+       bool is_sec1 = has_ftr_sec1(priv);
 
        /*
         * Master reset
@@ -203,8 +216,15 @@ static int init_device(struct device *dev)
        }
 
        /* enable channel done and error interrupts */
-       setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT);
-       setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);
+       if (is_sec1) {
+               clrbits32(priv->reg + TALITOS_IMR, TALITOS1_IMR_INIT);
+               clrbits32(priv->reg + TALITOS_IMR_LO, TALITOS1_IMR_LO_INIT);
+               /* disable parity error check in DEU (erroneous? test vect.) */
+               setbits32(priv->reg_deu + TALITOS_EUICR, TALITOS1_DEUICR_KPE);
+       } else {
+               setbits32(priv->reg + TALITOS_IMR, TALITOS2_IMR_INIT);
+               setbits32(priv->reg + TALITOS_IMR_LO, TALITOS2_IMR_LO_INIT);
+       }
 
        /* disable integrity check error interrupts (use writeback instead) */
        if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
@@ -349,8 +369,37 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
 /*
  * process completed requests for channels that have done status
  */
-#define DEF_TALITOS_DONE(name, ch_done_mask)                           \
-static void talitos_done_##name(unsigned long data)                    \
+#define DEF_TALITOS1_DONE(name, ch_done_mask)                          \
+static void talitos1_done_##name(unsigned long data)                   \
+{                                                                      \
+       struct device *dev = (struct device *)data;                     \
+       struct talitos_private *priv = dev_get_drvdata(dev);            \
+       unsigned long flags;                                            \
+                                                                       \
+       if (ch_done_mask & 0x10000000)                                  \
+               flush_channel(dev, 0, 0, 0);                    \
+       if (priv->num_channels == 1)                                    \
+               goto out;                                               \
+       if (ch_done_mask & 0x40000000)                                  \
+               flush_channel(dev, 1, 0, 0);                    \
+       if (ch_done_mask & 0x00010000)                                  \
+               flush_channel(dev, 2, 0, 0);                    \
+       if (ch_done_mask & 0x00040000)                                  \
+               flush_channel(dev, 3, 0, 0);                    \
+                                                                       \
+out:                                                                   \
+       /* At this point, all completed channels have been processed */ \
+       /* Unmask done interrupts for channels completed later on. */   \
+       spin_lock_irqsave(&priv->reg_lock, flags);                      \
+       clrbits32(priv->reg + TALITOS_IMR, ch_done_mask);               \
+       clrbits32(priv->reg + TALITOS_IMR_LO, TALITOS1_IMR_LO_INIT);    \
+       spin_unlock_irqrestore(&priv->reg_lock, flags);                 \
+}
+
+DEF_TALITOS1_DONE(4ch, TALITOS1_ISR_4CHDONE)
+
+#define DEF_TALITOS2_DONE(name, ch_done_mask)                          \
+static void talitos2_done_##name(unsigned long data)                   \
 {                                                                      \
        struct device *dev = (struct device *)data;                     \
        struct talitos_private *priv = dev_get_drvdata(dev);            \
@@ -372,12 +421,13 @@ out:                                                                      \
        /* Unmask done interrupts for channels completed later on. */   \
        spin_lock_irqsave(&priv->reg_lock, flags);                      \
        setbits32(priv->reg + TALITOS_IMR, ch_done_mask);               \
-       setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);     \
+       setbits32(priv->reg + TALITOS_IMR_LO, TALITOS2_IMR_LO_INIT);    \
        spin_unlock_irqrestore(&priv->reg_lock, flags);                 \
 }
-DEF_TALITOS_DONE(4ch, TALITOS_ISR_4CHDONE)
-DEF_TALITOS_DONE(ch0_2, TALITOS_ISR_CH_0_2_DONE)
-DEF_TALITOS_DONE(ch1_3, TALITOS_ISR_CH_1_3_DONE)
+
+DEF_TALITOS2_DONE(4ch, TALITOS2_ISR_4CHDONE)
+DEF_TALITOS2_DONE(ch0_2, TALITOS2_ISR_CH_0_2_DONE)
+DEF_TALITOS2_DONE(ch1_3, TALITOS2_ISR_CH_1_3_DONE)
 
 /*
  * locate current (offending) descriptor
@@ -492,13 +542,21 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
 {
        struct talitos_private *priv = dev_get_drvdata(dev);
        unsigned int timeout = TALITOS_TIMEOUT;
-       int ch, error, reset_dev = 0, reset_ch = 0;
+       int ch, error, reset_dev = 0;
        u32 v, v_lo;
+       bool is_sec1 = has_ftr_sec1(priv);
+       int reset_ch = is_sec1 ? 1 : 0; /* only SEC2 supports continuation */
 
        for (ch = 0; ch < priv->num_channels; ch++) {
                /* skip channels without errors */
-               if (!(isr & (1 << (ch * 2 + 1))))
-                       continue;
+               if (is_sec1) {
+                       /* bits 29, 31, 17, 19 */
+                       if (!(isr & (1 << (29 + (ch & 1) * 2 - (ch & 2) * 6))))
+                               continue;
+               } else {
+                       if (!(isr & (1 << (ch * 2 + 1))))
+                               continue;
+               }
 
                error = -EINVAL;
 
@@ -518,23 +576,28 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
                if (v_lo & TALITOS_CCPSR_LO_MDTE)
                        dev_err(dev, "master data transfer error\n");
                if (v_lo & TALITOS_CCPSR_LO_SGDLZ)
-                       dev_err(dev, "s/g data length zero error\n");
+                       dev_err(dev, is_sec1 ? "pointeur not complete error\n"
+                                            : "s/g data length zero error\n");
                if (v_lo & TALITOS_CCPSR_LO_FPZ)
-                       dev_err(dev, "fetch pointer zero error\n");
+                       dev_err(dev, is_sec1 ? "parity error\n"
+                                            : "fetch pointer zero error\n");
                if (v_lo & TALITOS_CCPSR_LO_IDH)
                        dev_err(dev, "illegal descriptor header error\n");
                if (v_lo & TALITOS_CCPSR_LO_IEU)
-                       dev_err(dev, "invalid execution unit error\n");
+                       dev_err(dev, is_sec1 ? "static assignment error\n"
+                                            : "invalid exec unit error\n");
                if (v_lo & TALITOS_CCPSR_LO_EU)
                        report_eu_error(dev, ch, current_desc_hdr(dev, ch));
-               if (v_lo & TALITOS_CCPSR_LO_GB)
-                       dev_err(dev, "gather boundary error\n");
-               if (v_lo & TALITOS_CCPSR_LO_GRL)
-                       dev_err(dev, "gather return/length error\n");
-               if (v_lo & TALITOS_CCPSR_LO_SB)
-                       dev_err(dev, "scatter boundary error\n");
-               if (v_lo & TALITOS_CCPSR_LO_SRL)
-                       dev_err(dev, "scatter return/length error\n");
+               if (!is_sec1) {
+                       if (v_lo & TALITOS_CCPSR_LO_GB)
+                               dev_err(dev, "gather boundary error\n");
+                       if (v_lo & TALITOS_CCPSR_LO_GRL)
+                               dev_err(dev, "gather return/length error\n");
+                       if (v_lo & TALITOS_CCPSR_LO_SB)
+                               dev_err(dev, "scatter boundary error\n");
+                       if (v_lo & TALITOS_CCPSR_LO_SRL)
+                               dev_err(dev, "scatter return/length error\n");
+               }
 
                flush_channel(dev, ch, error, reset_ch);
 
@@ -542,10 +605,10 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
                        reset_channel(dev, ch);
                } else {
                        setbits32(priv->chan[ch].reg + TALITOS_CCCR,
-                                 TALITOS_CCCR_CONT);
+                                 TALITOS2_CCCR_CONT);
                        setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, 0);
                        while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) &
-                              TALITOS_CCCR_CONT) && --timeout)
+                              TALITOS2_CCCR_CONT) && --timeout)
                                cpu_relax();
                        if (timeout == 0) {
                                dev_err(dev, "failed to restart channel %d\n",
@@ -554,9 +617,14 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
                        }
                }
        }
-       if (reset_dev || isr & ~TALITOS_ISR_4CHERR || isr_lo) {
-               dev_err(dev, "done overflow, internal time out, or rngu error: "
-                       "ISR 0x%08x_%08x\n", isr, isr_lo);
+       if (reset_dev || (is_sec1 && isr & ~TALITOS1_ISR_4CHERR) ||
+           (!is_sec1 && isr & ~TALITOS2_ISR_4CHERR) || isr_lo) {
+               if (is_sec1 && (isr_lo & TALITOS1_ISR_TEA_ERR))
+                       dev_err(dev, "TEA error: ISR 0x%08x_%08x\n",
+                               isr, isr_lo);
+               else
+                       dev_err(dev, "done overflow, internal time out, or "
+                               "rngu error: ISR 0x%08x_%08x\n", isr, isr_lo);
 
                /* purge request queues */
                for (ch = 0; ch < priv->num_channels; ch++)
@@ -567,8 +635,43 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
        }
 }
 
-#define DEF_TALITOS_INTERRUPT(name, ch_done_mask, ch_err_mask, tlet)          \
-static irqreturn_t talitos_interrupt_##name(int irq, void *data)              \
+#define DEF_TALITOS1_INTERRUPT(name, ch_done_mask, ch_err_mask, tlet)         \
+static irqreturn_t talitos1_interrupt_##name(int irq, void *data)             \
+{                                                                             \
+       struct device *dev = data;                                             \
+       struct talitos_private *priv = dev_get_drvdata(dev);                   \
+       u32 isr, isr_lo;                                                       \
+       unsigned long flags;                                                   \
+                                                                              \
+       spin_lock_irqsave(&priv->reg_lock, flags);                             \
+       isr = in_be32(priv->reg + TALITOS_ISR);                                \
+       isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);                          \
+       /* Acknowledge interrupt */                                            \
+       out_be32(priv->reg + TALITOS_ICR, isr & (ch_done_mask | ch_err_mask)); \
+       out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);                          \
+                                                                              \
+       if (unlikely(isr & ch_err_mask || isr_lo & TALITOS1_IMR_LO_INIT)) {    \
+               spin_unlock_irqrestore(&priv->reg_lock, flags);                \
+               talitos_error(dev, isr & ch_err_mask, isr_lo);                 \
+       }                                                                      \
+       else {                                                                 \
+               if (likely(isr & ch_done_mask)) {                              \
+                       /* mask further done interrupts. */                    \
+                       setbits32(priv->reg + TALITOS_IMR, ch_done_mask);      \
+                       /* done_task will unmask done interrupts at exit */    \
+                       tasklet_schedule(&priv->done_task[tlet]);              \
+               }                                                              \
+               spin_unlock_irqrestore(&priv->reg_lock, flags);                \
+       }                                                                      \
+                                                                              \
+       return (isr & (ch_done_mask | ch_err_mask) || isr_lo) ? IRQ_HANDLED :  \
+                                                               IRQ_NONE;      \
+}
+
+DEF_TALITOS1_INTERRUPT(4ch, TALITOS1_ISR_4CHDONE, TALITOS1_ISR_4CHERR, 0)
+
+#define DEF_TALITOS2_INTERRUPT(name, ch_done_mask, ch_err_mask, tlet)         \
+static irqreturn_t talitos2_interrupt_##name(int irq, void *data)             \
 {                                                                             \
        struct device *dev = data;                                             \
        struct talitos_private *priv = dev_get_drvdata(dev);                   \
@@ -599,9 +702,12 @@ static irqreturn_t talitos_interrupt_##name(int irq, void *data)          \
        return (isr & (ch_done_mask | ch_err_mask) || isr_lo) ? IRQ_HANDLED :  \
                                                                IRQ_NONE;      \
 }
-DEF_TALITOS_INTERRUPT(4ch, TALITOS_ISR_4CHDONE, TALITOS_ISR_4CHERR, 0)
-DEF_TALITOS_INTERRUPT(ch0_2, TALITOS_ISR_CH_0_2_DONE, TALITOS_ISR_CH_0_2_ERR, 0)
-DEF_TALITOS_INTERRUPT(ch1_3, TALITOS_ISR_CH_1_3_DONE, TALITOS_ISR_CH_1_3_ERR, 1)
+
+DEF_TALITOS2_INTERRUPT(4ch, TALITOS2_ISR_4CHDONE, TALITOS2_ISR_4CHERR, 0)
+DEF_TALITOS2_INTERRUPT(ch0_2, TALITOS2_ISR_CH_0_2_DONE, TALITOS2_ISR_CH_0_2_ERR,
+                      0)
+DEF_TALITOS2_INTERRUPT(ch1_3, TALITOS2_ISR_CH_1_3_DONE, TALITOS2_ISR_CH_1_3_ERR,
+                      1)
 
 /*
  * hwrng
@@ -2639,29 +2745,35 @@ static int talitos_probe_irq(struct platform_device *ofdev)
        struct device_node *np = ofdev->dev.of_node;
        struct talitos_private *priv = dev_get_drvdata(dev);
        int err;
+       bool is_sec1 = has_ftr_sec1(priv);
 
        priv->irq[0] = irq_of_parse_and_map(np, 0);
        if (!priv->irq[0]) {
                dev_err(dev, "failed to map irq\n");
                return -EINVAL;
        }
+       if (is_sec1) {
+               err = request_irq(priv->irq[0], talitos1_interrupt_4ch, 0,
+                                 dev_driver_string(dev), dev);
+               goto primary_out;
+       }
 
        priv->irq[1] = irq_of_parse_and_map(np, 1);
 
        /* get the primary irq line */
        if (!priv->irq[1]) {
-               err = request_irq(priv->irq[0], talitos_interrupt_4ch, 0,
+               err = request_irq(priv->irq[0], talitos2_interrupt_4ch, 0,
                                  dev_driver_string(dev), dev);
                goto primary_out;
        }
 
-       err = request_irq(priv->irq[0], talitos_interrupt_ch0_2, 0,
+       err = request_irq(priv->irq[0], talitos2_interrupt_ch0_2, 0,
                          dev_driver_string(dev), dev);
        if (err)
                goto primary_out;
 
        /* get the secondary irq line */
-       err = request_irq(priv->irq[1], talitos_interrupt_ch1_3, 0,
+       err = request_irq(priv->irq[1], talitos2_interrupt_ch1_3, 0,
                          dev_driver_string(dev), dev);
        if (err) {
                dev_err(dev, "failed to request secondary irq\n");
@@ -2702,20 +2814,6 @@ static int talitos_probe(struct platform_device *ofdev)
 
        spin_lock_init(&priv->reg_lock);
 
-       err = talitos_probe_irq(ofdev);
-       if (err)
-               goto err_out;
-
-       if (!priv->irq[1]) {
-               tasklet_init(&priv->done_task[0], talitos_done_4ch,
-                            (unsigned long)dev);
-       } else {
-               tasklet_init(&priv->done_task[0], talitos_done_ch0_2,
-                            (unsigned long)dev);
-               tasklet_init(&priv->done_task[1], talitos_done_ch1_3,
-                            (unsigned long)dev);
-       }
-
        priv->reg = of_iomap(np, 0);
        if (!priv->reg) {
                dev_err(dev, "failed to of_iomap\n");
@@ -2783,6 +2881,25 @@ static int talitos_probe(struct platform_device *ofdev)
                stride = TALITOS2_CH_STRIDE;
        }
 
+       err = talitos_probe_irq(ofdev);
+       if (err)
+               goto err_out;
+
+       if (of_device_is_compatible(np, "fsl,sec1.0")) {
+               tasklet_init(&priv->done_task[0], talitos1_done_4ch,
+                            (unsigned long)dev);
+       } else {
+               if (!priv->irq[1]) {
+                       tasklet_init(&priv->done_task[0], talitos2_done_4ch,
+                                    (unsigned long)dev);
+               } else {
+                       tasklet_init(&priv->done_task[0], talitos2_done_ch0_2,
+                                    (unsigned long)dev);
+                       tasklet_init(&priv->done_task[1], talitos2_done_ch1_3,
+                                    (unsigned long)dev);
+               }
+       }
+
        priv->chan = kzalloc(sizeof(struct talitos_channel) *
                             priv->num_channels, GFP_KERNEL);
        if (!priv->chan) {