blob: 8161087b50c0e04942d386c6d1bc5dda784c9821 [file] [log] [blame]
Vignesh Raghavendra2736c672019-10-23 13:30:01 +05301// SPDX-License-Identifier: GPL-2.0
2//
Nishanth Menoneaa39c62023-11-01 15:56:03 -05003// Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
Vignesh Raghavendra2736c672019-10-23 13:30:01 +05304// 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>
Simon Glass9bc15642020-02-03 07:36:16 -070011#include <dm/device_compat.h>
Vignesh Raghavendra2736c672019-10-23 13:30:01 +053012
13#define FSS_SYSC_REG 0x4
14
15#define HYPERBUS_CALIB_COUNT 25
16
17struct am654_hbmc_priv {
18 void __iomem *mmiobase;
19 bool calibrated;
20};
21
22/* Calibrate by looking for "QRY" string within the CFI space */
23static 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
54static 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
61static int am654_hbmc_bind(struct udevice *dev)
62{
63 return dm_scan_fdt_dev(dev);
64}
65
66static 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
92static const struct udevice_id am654_hbmc_dt_ids[] = {
93 {
94 .compatible = "ti,am654-hbmc",
95 },
96 { /* end of table */ }
97};
98
99U_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,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700105 .priv_auto = sizeof(struct am654_hbmc_priv),
Vignesh Raghavendra2736c672019-10-23 13:30:01 +0530106};