]>
Commit | Line | Data |
---|---|---|
c2dfd0a4 VR |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
a94a4071 | 3 | // Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ |
c2dfd0a4 VR |
4 | // Author: Vignesh Raghavendra <vigneshr@ti.com> |
5 | ||
d678a59d | 6 | #include <common.h> |
c2dfd0a4 VR |
7 | #include <asm/io.h> |
8 | #include <dm.h> | |
9 | #include <regmap.h> | |
10 | #include <syscon.h> | |
336d4615 | 11 | #include <dm/device_compat.h> |
c2dfd0a4 VR |
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, | |
41575d8e | 105 | .priv_auto = sizeof(struct am654_hbmc_priv), |
c2dfd0a4 | 106 | }; |