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