OSDN Git Service

Merge branch 'for-5.7' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[tomoyo/tomoyo-test1.git] / drivers / spi / spi-bcm-qspi.c
index 4c0d0cc..681d090 100644 (file)
@@ -91,6 +91,7 @@
 #define MSPI_MSPI_STATUS                       0x020
 #define MSPI_CPTQP                             0x024
 #define MSPI_SPCR3                             0x028
+#define MSPI_REV                               0x02c
 #define MSPI_TXRAM                             0x040
 #define MSPI_RXRAM                             0x0c0
 #define MSPI_CDRAM                             0x140
 #define MSPI_SPCR2_SPE                         BIT(6)
 #define MSPI_SPCR2_CONT_AFTER_CMD              BIT(7)
 
+#define MSPI_SPCR3_FASTBR                      BIT(0)
+#define MSPI_SPCR3_FASTDT                      BIT(1)
+#define MSPI_SPCR3_SYSCLKSEL_MASK              GENMASK(11, 10)
+#define MSPI_SPCR3_SYSCLKSEL_27                        (MSPI_SPCR3_SYSCLKSEL_MASK & \
+                                                ~(BIT(10) | BIT(11)))
+#define MSPI_SPCR3_SYSCLKSEL_108               (MSPI_SPCR3_SYSCLKSEL_MASK & \
+                                                BIT(11))
+
 #define MSPI_MSPI_STATUS_SPIF                  BIT(0)
 
 #define INTR_BASE_BIT_SHIFT                    0x02
 #define INTR_COUNT                             0x07
 
 #define NUM_CHIPSELECT                         4
-#define QSPI_SPBR_MIN                          8U
 #define QSPI_SPBR_MAX                          255U
+#define MSPI_BASE_FREQ                         27000000UL
 
 #define OPCODE_DIOR                            0xBB
 #define OPCODE_QIOR                            0xEB
@@ -217,6 +226,9 @@ struct bcm_qspi {
        struct bcm_qspi_dev_id *dev_ids;
        struct completion mspi_done;
        struct completion bspi_done;
+       u8 mspi_maj_rev;
+       u8 mspi_min_rev;
+       bool mspi_spcr3_sysclk;
 };
 
 static inline bool has_bspi(struct bcm_qspi *qspi)
@@ -224,6 +236,36 @@ static inline bool has_bspi(struct bcm_qspi *qspi)
        return qspi->bspi_mode;
 }
 
+/* hardware supports spcr3 and fast baud-rate  */
+static inline bool bcm_qspi_has_fastbr(struct bcm_qspi *qspi)
+{
+       if (!has_bspi(qspi) &&
+           ((qspi->mspi_maj_rev >= 1) &&
+            (qspi->mspi_min_rev >= 5)))
+               return true;
+
+       return false;
+}
+
+/* hardware supports sys clk 108Mhz  */
+static inline bool bcm_qspi_has_sysclk_108(struct bcm_qspi *qspi)
+{
+       if (!has_bspi(qspi) && (qspi->mspi_spcr3_sysclk ||
+           ((qspi->mspi_maj_rev >= 1) &&
+            (qspi->mspi_min_rev >= 6))))
+               return true;
+
+       return false;
+}
+
+static inline int bcm_qspi_spbr_min(struct bcm_qspi *qspi)
+{
+       if (bcm_qspi_has_fastbr(qspi))
+               return 1;
+       else
+               return 8;
+}
+
 /* Read qspi controller register*/
 static inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type,
                                unsigned int offset)
@@ -531,16 +573,39 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
        if (xp->speed_hz)
                spbr = qspi->base_clk / (2 * xp->speed_hz);
 
-       spcr = clamp_val(spbr, QSPI_SPBR_MIN, QSPI_SPBR_MAX);
+       spcr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX);
        bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spcr);
 
-       spcr = MSPI_MASTER_BIT;
+       if (!qspi->mspi_maj_rev)
+               /* legacy controller */
+               spcr = MSPI_MASTER_BIT;
+       else
+               spcr = 0;
+
        /* for 16 bit the data should be zero */
        if (xp->bits_per_word != 16)
                spcr |= xp->bits_per_word << 2;
        spcr |= xp->mode & 3;
+
        bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_MSB, spcr);
 
+       if (bcm_qspi_has_fastbr(qspi)) {
+               spcr = 0;
+
+               /* enable fastbr */
+               spcr |= MSPI_SPCR3_FASTBR;
+
+               if (bcm_qspi_has_sysclk_108(qspi)) {
+                       /* SYSCLK_108 */
+                       spcr |= MSPI_SPCR3_SYSCLKSEL_108;
+                       qspi->base_clk = MSPI_BASE_FREQ * 4;
+                       /* Change spbr as we changed sysclk */
+                       bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, 4);
+               }
+
+               bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr);
+       }
+
        qspi->last_parms = *xp;
 }
 
@@ -1195,8 +1260,51 @@ static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
        .exec_op = bcm_qspi_exec_mem_op,
 };
 
+struct bcm_qspi_data {
+       bool    has_mspi_rev;
+       bool    has_spcr3_sysclk;
+};
+
+static const struct bcm_qspi_data bcm_qspi_no_rev_data = {
+       .has_mspi_rev   = false,
+       .has_spcr3_sysclk = false,
+};
+
+static const struct bcm_qspi_data bcm_qspi_rev_data = {
+       .has_mspi_rev   = true,
+       .has_spcr3_sysclk = false,
+};
+
+static const struct bcm_qspi_data bcm_qspi_spcr3_data = {
+       .has_mspi_rev   = true,
+       .has_spcr3_sysclk = true,
+};
+
 static const struct of_device_id bcm_qspi_of_match[] = {
-       { .compatible = "brcm,spi-bcm-qspi" },
+       {
+               .compatible = "brcm,spi-bcm7425-qspi",
+               .data = &bcm_qspi_no_rev_data,
+       },
+       {
+               .compatible = "brcm,spi-bcm7429-qspi",
+               .data = &bcm_qspi_no_rev_data,
+       },
+       {
+               .compatible = "brcm,spi-bcm7435-qspi",
+               .data = &bcm_qspi_no_rev_data,
+       },
+       {
+               .compatible = "brcm,spi-bcm-qspi",
+               .data = &bcm_qspi_rev_data,
+       },
+       {
+               .compatible = "brcm,spi-bcm7216-qspi",
+               .data = &bcm_qspi_spcr3_data,
+       },
+       {
+               .compatible = "brcm,spi-bcm7278-qspi",
+               .data = &bcm_qspi_spcr3_data,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, bcm_qspi_of_match);
@@ -1204,12 +1312,15 @@ MODULE_DEVICE_TABLE(of, bcm_qspi_of_match);
 int bcm_qspi_probe(struct platform_device *pdev,
                   struct bcm_qspi_soc_intc *soc_intc)
 {
+       const struct of_device_id *of_id = NULL;
+       const struct bcm_qspi_data *data;
        struct device *dev = &pdev->dev;
        struct bcm_qspi *qspi;
        struct spi_master *master;
        struct resource *res;
        int irq, ret = 0, num_ints = 0;
        u32 val;
+       u32 rev = 0;
        const char *name = NULL;
        int num_irqs = ARRAY_SIZE(qspi_irq_tab);
 
@@ -1217,9 +1328,12 @@ int bcm_qspi_probe(struct platform_device *pdev,
        if (!dev->of_node)
                return -ENODEV;
 
-       if (!of_match_node(bcm_qspi_of_match, dev->of_node))
+       of_id = of_match_node(bcm_qspi_of_match, dev->of_node);
+       if (!of_id)
                return -ENODEV;
 
+       data = of_id->data;
+
        master = spi_alloc_master(dev, sizeof(struct bcm_qspi));
        if (!master) {
                dev_err(dev, "error allocating spi_master\n");
@@ -1352,7 +1466,19 @@ int bcm_qspi_probe(struct platform_device *pdev,
        }
 
        qspi->base_clk = clk_get_rate(qspi->clk);
-       qspi->max_speed_hz = qspi->base_clk / (QSPI_SPBR_MIN * 2);
+
+       if (data->has_mspi_rev) {
+               rev = bcm_qspi_read(qspi, MSPI, MSPI_REV);
+               /* some older revs do not have a MSPI_REV register */
+               if ((rev & 0xff) == 0xff)
+                       rev = 0;
+       }
+
+       qspi->mspi_maj_rev = (rev >> 4) & 0xf;
+       qspi->mspi_min_rev = rev & 0xf;
+       qspi->mspi_spcr3_sysclk = data->has_spcr3_sysclk;
+
+       qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
 
        bcm_qspi_hw_init(qspi);
        init_completion(&qspi->mspi_done);