Merge branch '2020-06-03-misc-bugfixes'
[oweals/u-boot.git] / drivers / mtd / hbmc-am654.c
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
4 // Author: Vignesh Raghavendra <vigneshr@ti.com>
5
6 #include <common.h>
7 #include <asm/io.h>
8 #include <dm.h>
9 #include <regmap.h>
10 #include <syscon.h>
11 #include <dm/device_compat.h>
12
13 #define FSS_SYSC_REG    0x4
14
15 #define HYPERBUS_CALIB_COUNT 25
16
17 struct am654_hbmc_priv {
18         void __iomem *mmiobase;
19         bool calibrated;
20 };
21
22 /* Calibrate by looking for "QRY" string within the CFI space */
23 static int am654_hyperbus_calibrate(struct udevice *dev)
24 {
25         struct am654_hbmc_priv *priv = dev_get_priv(dev);
26         int count = HYPERBUS_CALIB_COUNT;
27         int pass_count = 0;
28         u16 qry[3];
29
30         if (priv->calibrated)
31                 return 0;
32
33         writew(0xF0, priv->mmiobase);
34         writew(0x98, priv->mmiobase + 0xaa);
35
36         while (count--) {
37                 qry[0] = readw(priv->mmiobase + 0x20);
38                 qry[1] = readw(priv->mmiobase + 0x22);
39                 qry[2] = readw(priv->mmiobase + 0x24);
40
41                 if (qry[0] == 'Q' && qry[1] == 'R' && qry[2] == 'Y')
42                         pass_count++;
43                 else
44                         pass_count = 0;
45                 if (pass_count == 5)
46                         break;
47         }
48         writew(0xF0, priv->mmiobase);
49         writew(0xFF, priv->mmiobase);
50
51         return pass_count == 5;
52 }
53
54 static int am654_select_hbmc(struct udevice *dev)
55 {
56         struct regmap *regmap = syscon_get_regmap(dev_get_parent(dev));
57
58         return regmap_update_bits(regmap, FSS_SYSC_REG, 0x2, 0x2);
59 }
60
61 static int am654_hbmc_bind(struct udevice *dev)
62 {
63         return dm_scan_fdt_dev(dev);
64 }
65
66 static int am654_hbmc_probe(struct udevice *dev)
67 {
68         struct am654_hbmc_priv *priv = dev_get_priv(dev);
69         int ret;
70
71         priv->mmiobase = devfdt_remap_addr_index(dev, 1);
72         if (dev_read_bool(dev, "mux-controls")) {
73                 ret = am654_select_hbmc(dev);
74                 if (ret) {
75                         dev_err(dev, "Failed to select HBMC mux\n");
76                         return ret;
77                 }
78         }
79
80         if (!priv->calibrated) {
81                 ret = am654_hyperbus_calibrate(dev);
82                 if (!ret) {
83                         dev_err(dev, "Calibration Failed\n");
84                         return -EIO;
85                 }
86         }
87         priv->calibrated = true;
88
89         return 0;
90 }
91
92 static const struct udevice_id am654_hbmc_dt_ids[] = {
93         {
94                 .compatible = "ti,am654-hbmc",
95         },
96         { /* end of table */ }
97 };
98
99 U_BOOT_DRIVER(hbmc_am654) = {
100         .name   = "hbmc-am654",
101         .id     = UCLASS_MTD,
102         .of_match = am654_hbmc_dt_ids,
103         .probe = am654_hbmc_probe,
104         .bind = am654_hbmc_bind,
105         .priv_auto_alloc_size = sizeof(struct am654_hbmc_priv),
106 };