blob: 98988a8e24da412a43a5e54d720491b7cf5f48f8 [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>
Anurag Dutta91fd1912024-11-29 17:01:30 +05308#include <mux.h>
Vignesh Raghavendra2736c672019-10-23 13:30:01 +05309#include <regmap.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{
Anurag Dutta91fd1912024-11-29 17:01:30 +053055 struct mux_control *mux_ctl;
56 int ret;
Vignesh Raghavendra2736c672019-10-23 13:30:01 +053057
Anurag Dutta91fd1912024-11-29 17:01:30 +053058 ret = mux_get_by_index(dev, 0, &mux_ctl);
59 if (!ret)
60 ret = mux_control_select(mux_ctl, 1);
61 return ret;
Vignesh Raghavendra2736c672019-10-23 13:30:01 +053062}
63
64static int am654_hbmc_bind(struct udevice *dev)
65{
66 return dm_scan_fdt_dev(dev);
67}
68
69static int am654_hbmc_probe(struct udevice *dev)
70{
71 struct am654_hbmc_priv *priv = dev_get_priv(dev);
72 int ret;
73
74 priv->mmiobase = devfdt_remap_addr_index(dev, 1);
75 if (dev_read_bool(dev, "mux-controls")) {
76 ret = am654_select_hbmc(dev);
77 if (ret) {
78 dev_err(dev, "Failed to select HBMC mux\n");
79 return ret;
80 }
81 }
82
83 if (!priv->calibrated) {
84 ret = am654_hyperbus_calibrate(dev);
85 if (!ret) {
86 dev_err(dev, "Calibration Failed\n");
87 return -EIO;
88 }
89 }
90 priv->calibrated = true;
91
92 return 0;
93}
94
95static const struct udevice_id am654_hbmc_dt_ids[] = {
96 {
97 .compatible = "ti,am654-hbmc",
98 },
99 { /* end of table */ }
100};
101
102U_BOOT_DRIVER(hbmc_am654) = {
103 .name = "hbmc-am654",
104 .id = UCLASS_MTD,
105 .of_match = am654_hbmc_dt_ids,
106 .probe = am654_hbmc_probe,
107 .bind = am654_hbmc_bind,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700108 .priv_auto = sizeof(struct am654_hbmc_priv),
Vignesh Raghavendra2736c672019-10-23 13:30:01 +0530109};