blob: 599beda30d5550517018061e3e4a2f90f1e20c18 [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
Vignesh Raghavendra2736c672019-10-23 13:30:01 +05306#include <asm/io.h>
7#include <dm.h>
8#include <regmap.h>
9#include <syscon.h>
Simon Glass9bc15642020-02-03 07:36:16 -070010#include <dm/device_compat.h>
Vignesh Raghavendra2736c672019-10-23 13:30:01 +053011
12#define FSS_SYSC_REG 0x4
13
14#define HYPERBUS_CALIB_COUNT 25
15
16struct am654_hbmc_priv {
17 void __iomem *mmiobase;
18 bool calibrated;
19};
20
21/* Calibrate by looking for "QRY" string within the CFI space */
22static 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
53static 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
60static int am654_hbmc_bind(struct udevice *dev)
61{
62 return dm_scan_fdt_dev(dev);
63}
64
65static 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
91static const struct udevice_id am654_hbmc_dt_ids[] = {
92 {
93 .compatible = "ti,am654-hbmc",
94 },
95 { /* end of table */ }
96};
97
98U_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,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700104 .priv_auto = sizeof(struct am654_hbmc_priv),
Vignesh Raghavendra2736c672019-10-23 13:30:01 +0530105};