sifive_prci.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. /*-
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2019 Axiado Corporation
  5. * All rights reserved.
  6. * Copyright (c) 2021 Jessica Clarke <jrtc27@FreeBSD.org>
  7. *
  8. * This software was developed in part by Kristof Provost under contract for
  9. * Axiado Corporation.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. */
  32. #include <sys/param.h>
  33. #include <sys/systm.h>
  34. #include <sys/bus.h>
  35. #include <sys/kernel.h>
  36. #include <sys/lock.h>
  37. #include <sys/module.h>
  38. #include <sys/mutex.h>
  39. #include <sys/rman.h>
  40. #include <machine/bus.h>
  41. #include <machine/cpu.h>
  42. #include <dev/clk/clk.h>
  43. #include <dev/clk/clk_fixed.h>
  44. #include <dev/clk/clk_gate.h>
  45. #include <dev/ofw/ofw_bus.h>
  46. #include <dev/ofw/ofw_bus_subr.h>
  47. #include <dev/ofw/openfirm.h>
  48. #include "clkdev_if.h"
  49. #include "hwreset_if.h"
  50. static struct resource_spec prci_spec[] = {
  51. { SYS_RES_MEMORY, 0, RF_ACTIVE },
  52. RESOURCE_SPEC_END
  53. };
  54. struct prci_softc {
  55. device_t dev;
  56. struct mtx mtx;
  57. struct clkdom *clkdom;
  58. struct resource *res;
  59. bus_space_tag_t bst;
  60. bus_space_handle_t bsh;
  61. int nresets;
  62. };
  63. struct prci_clk_pll_sc {
  64. struct prci_softc *parent_sc;
  65. uint32_t reg;
  66. };
  67. struct prci_clk_div_sc {
  68. struct prci_softc *parent_sc;
  69. uint32_t reg;
  70. uint32_t bias;
  71. };
  72. #define PRCI_LOCK(sc) mtx_lock(&(sc)->mtx)
  73. #define PRCI_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
  74. #define PRCI_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED);
  75. #define PRCI_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED);
  76. #define PRCI_PLL_DIVR_MASK 0x3f
  77. #define PRCI_PLL_DIVR_SHIFT 0
  78. #define PRCI_PLL_DIVF_MASK 0x7fc0
  79. #define PRCI_PLL_DIVF_SHIFT 6
  80. #define PRCI_PLL_DIVQ_MASK 0x38000
  81. #define PRCI_PLL_DIVQ_SHIFT 15
  82. /* Called devicesresetreg on the FU540 */
  83. #define PRCI_DEVICES_RESET_N 0x28
  84. #define PRCI_READ(_sc, _reg) \
  85. bus_space_read_4((_sc)->bst, (_sc)->bsh, (_reg))
  86. #define PRCI_WRITE(_sc, _reg, _val) \
  87. bus_space_write_4((_sc)->bst, (_sc)->bsh, (_reg), (_val))
  88. struct prci_pll_def {
  89. uint32_t id;
  90. const char *name;
  91. uint32_t reg;
  92. };
  93. #define PLL(_id, _name, _base) \
  94. { \
  95. .id = (_id), \
  96. .name = (_name), \
  97. .reg = (_base), \
  98. }
  99. #define PLL_END PLL(0, NULL, 0)
  100. struct prci_div_def {
  101. uint32_t id;
  102. const char *name;
  103. const char *parent_name;
  104. uint32_t reg;
  105. uint32_t bias;
  106. };
  107. #define DIV(_id, _name, _parent_name, _base, _bias) \
  108. { \
  109. .id = (_id), \
  110. .name = (_name), \
  111. .parent_name = (_parent_name), \
  112. .reg = (_base), \
  113. .bias = (_bias), \
  114. }
  115. #define DIV_END DIV(0, NULL, NULL, 0, 0)
  116. struct prci_gate_def {
  117. uint32_t id;
  118. const char *name;
  119. const char *parent_name;
  120. uint32_t reg;
  121. };
  122. #define GATE(_id, _name, _parent_name, _base) \
  123. { \
  124. .id = (_id), \
  125. .name = (_name), \
  126. .parent_name = (_parent_name), \
  127. .reg = (_base), \
  128. }
  129. #define GATE_END GATE(0, NULL, NULL, 0)
  130. struct prci_config {
  131. struct prci_pll_def *pll_clks;
  132. struct prci_div_def *div_clks;
  133. struct prci_gate_def *gate_clks;
  134. struct clk_fixed_def *tlclk_def;
  135. int nresets;
  136. };
  137. /* FU540 clock numbers */
  138. #define FU540_PRCI_CORECLK 0
  139. #define FU540_PRCI_DDRCLK 1
  140. #define FU540_PRCI_GEMGXLCLK 2
  141. #define FU540_PRCI_TLCLK 3
  142. /* FU540 registers */
  143. #define FU540_PRCI_COREPLL_CFG0 0x4
  144. #define FU540_PRCI_DDRPLL_CFG0 0xC
  145. #define FU540_PRCI_GEMGXLPLL_CFG0 0x1C
  146. /* FU540 PLL clocks */
  147. static struct prci_pll_def fu540_pll_clks[] = {
  148. PLL(FU540_PRCI_CORECLK, "coreclk", FU540_PRCI_COREPLL_CFG0),
  149. PLL(FU540_PRCI_DDRCLK, "ddrclk", FU540_PRCI_DDRPLL_CFG0),
  150. PLL(FU540_PRCI_GEMGXLCLK, "gemgxlclk", FU540_PRCI_GEMGXLPLL_CFG0),
  151. PLL_END
  152. };
  153. /* FU540 fixed divisor clock TLCLK. */
  154. static struct clk_fixed_def fu540_tlclk_def = {
  155. .clkdef.id = FU540_PRCI_TLCLK,
  156. .clkdef.name = "tlclk",
  157. .clkdef.parent_names = (const char *[]){"coreclk"},
  158. .clkdef.parent_cnt = 1,
  159. .clkdef.flags = CLK_NODE_STATIC_STRINGS,
  160. .mult = 1,
  161. .div = 2,
  162. };
  163. /* FU540 config */
  164. struct prci_config fu540_prci_config = {
  165. .pll_clks = fu540_pll_clks,
  166. .tlclk_def = &fu540_tlclk_def,
  167. .nresets = 6,
  168. };
  169. /* FU740 clock numbers */
  170. #define FU740_PRCI_CORECLK 0
  171. #define FU740_PRCI_DDRCLK 1
  172. #define FU740_PRCI_GEMGXLCLK 2
  173. #define FU740_PRCI_DVFSCORECLK 3
  174. #define FU740_PRCI_HFPCLK 4
  175. #define FU740_PRCI_CLTXCLK 5
  176. #define FU740_PRCI_TLCLK 6
  177. #define FU740_PRCI_PCLK 7
  178. #define FU740_PRCI_PCIEAUXCLK 8
  179. /* FU740 registers */
  180. #define FU740_PRCI_COREPLL_CFG0 0x4
  181. #define FU740_PRCI_DDRPLL_CFG0 0xC
  182. #define FU740_PRCI_PCIEAUX_GATE 0x14
  183. #define FU740_PRCI_GEMGXLPLL_CFG0 0x1C
  184. #define FU740_PRCI_DVFSCOREPLL_CFG0 0x38
  185. #define FU740_PRCI_HFPCLKPLL_CFG0 0x50
  186. #define FU740_PRCI_CLTXPLL_CFG0 0x30
  187. #define FU740_PRCI_HFPCLK_DIV 0x5C
  188. /* FU740 PLL clocks */
  189. static struct prci_pll_def fu740_pll_clks[] = {
  190. PLL(FU740_PRCI_CORECLK, "coreclk", FU740_PRCI_COREPLL_CFG0),
  191. PLL(FU740_PRCI_DDRCLK, "ddrclk", FU740_PRCI_DDRPLL_CFG0),
  192. PLL(FU740_PRCI_GEMGXLCLK, "gemgxlclk", FU740_PRCI_GEMGXLPLL_CFG0),
  193. PLL(FU740_PRCI_DVFSCORECLK, "dvfscoreclk", FU740_PRCI_DVFSCOREPLL_CFG0),
  194. PLL(FU740_PRCI_HFPCLK, "hfpclk", FU740_PRCI_HFPCLKPLL_CFG0),
  195. PLL(FU740_PRCI_CLTXCLK, "cltxclk", FU740_PRCI_CLTXPLL_CFG0),
  196. PLL_END
  197. };
  198. /* FU740 divisor clocks */
  199. static struct prci_div_def fu740_div_clks[] = {
  200. DIV(FU740_PRCI_PCLK, "pclk", "hfpclk", FU740_PRCI_HFPCLK_DIV, 2),
  201. DIV_END
  202. };
  203. /* FU740 gated clocks */
  204. static struct prci_gate_def fu740_gate_clks[] = {
  205. GATE(FU740_PRCI_PCIEAUXCLK, "pcieauxclk", "hfclk", FU740_PRCI_PCIEAUX_GATE),
  206. GATE_END
  207. };
  208. /* FU740 fixed divisor clock TLCLK. */
  209. static struct clk_fixed_def fu740_tlclk_def = {
  210. .clkdef.id = FU740_PRCI_TLCLK,
  211. .clkdef.name = "tlclk",
  212. .clkdef.parent_names = (const char *[]){"coreclk"},
  213. .clkdef.parent_cnt = 1,
  214. .clkdef.flags = CLK_NODE_STATIC_STRINGS,
  215. .mult = 1,
  216. .div = 2,
  217. };
  218. /* FU740 config */
  219. struct prci_config fu740_prci_config = {
  220. .pll_clks = fu740_pll_clks,
  221. .div_clks = fu740_div_clks,
  222. .gate_clks = fu740_gate_clks,
  223. .tlclk_def = &fu740_tlclk_def,
  224. .nresets = 7,
  225. };
  226. static struct ofw_compat_data compat_data[] = {
  227. { "sifive,aloeprci0", (uintptr_t)&fu540_prci_config },
  228. { "sifive,ux00prci0", (uintptr_t)&fu540_prci_config },
  229. { "sifive,fu540-c000-prci", (uintptr_t)&fu540_prci_config },
  230. { "sifive,fu740-c000-prci", (uintptr_t)&fu740_prci_config },
  231. { NULL, 0 },
  232. };
  233. static int
  234. prci_clk_pll_init(struct clknode *clk, device_t dev)
  235. {
  236. clknode_init_parent_idx(clk, 0);
  237. return (0);
  238. }
  239. static int
  240. prci_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
  241. {
  242. struct prci_clk_pll_sc *sc;
  243. struct clknode *parent_clk;
  244. uint32_t val;
  245. uint64_t refclk, divf, divq, divr;
  246. int err;
  247. KASSERT(freq != NULL, ("freq cannot be NULL"));
  248. sc = clknode_get_softc(clk);
  249. PRCI_LOCK(sc->parent_sc);
  250. /* Get refclock frequency. */
  251. parent_clk = clknode_get_parent(clk);
  252. err = clknode_get_freq(parent_clk, &refclk);
  253. if (err) {
  254. device_printf(sc->parent_sc->dev,
  255. "Failed to get refclk frequency\n");
  256. PRCI_UNLOCK(sc->parent_sc);
  257. return (err);
  258. }
  259. /* Calculate the PLL output */
  260. val = PRCI_READ(sc->parent_sc, sc->reg);
  261. divf = (val & PRCI_PLL_DIVF_MASK) >> PRCI_PLL_DIVF_SHIFT;
  262. divq = (val & PRCI_PLL_DIVQ_MASK) >> PRCI_PLL_DIVQ_SHIFT;
  263. divr = (val & PRCI_PLL_DIVR_MASK) >> PRCI_PLL_DIVR_SHIFT;
  264. *freq = refclk / (divr + 1) * (2 * (divf + 1)) / (1 << divq);
  265. PRCI_UNLOCK(sc->parent_sc);
  266. return (0);
  267. }
  268. static clknode_method_t prci_clk_pll_clknode_methods[] = {
  269. CLKNODEMETHOD(clknode_init, prci_clk_pll_init),
  270. CLKNODEMETHOD(clknode_recalc_freq, prci_clk_pll_recalc),
  271. CLKNODEMETHOD_END
  272. };
  273. DEFINE_CLASS_1(prci_clk_pll_clknode, prci_clk_pll_clknode_class,
  274. prci_clk_pll_clknode_methods, sizeof(struct prci_clk_pll_sc),
  275. clknode_class);
  276. static int
  277. prci_clk_div_init(struct clknode *clk, device_t dev)
  278. {
  279. clknode_init_parent_idx(clk, 0);
  280. return (0);
  281. }
  282. static int
  283. prci_clk_div_recalc(struct clknode *clk, uint64_t *freq)
  284. {
  285. struct prci_clk_div_sc *sc;
  286. struct clknode *parent_clk;
  287. uint32_t div;
  288. uint64_t refclk;
  289. int err;
  290. KASSERT(freq != NULL, ("freq cannot be NULL"));
  291. sc = clknode_get_softc(clk);
  292. PRCI_LOCK(sc->parent_sc);
  293. /* Get refclock frequency. */
  294. parent_clk = clknode_get_parent(clk);
  295. err = clknode_get_freq(parent_clk, &refclk);
  296. if (err) {
  297. device_printf(sc->parent_sc->dev,
  298. "Failed to get refclk frequency\n");
  299. PRCI_UNLOCK(sc->parent_sc);
  300. return (err);
  301. }
  302. /* Calculate the divisor output */
  303. div = PRCI_READ(sc->parent_sc, sc->reg);
  304. *freq = refclk / (div + sc->bias);
  305. PRCI_UNLOCK(sc->parent_sc);
  306. return (0);
  307. }
  308. static clknode_method_t prci_clk_div_clknode_methods[] = {
  309. CLKNODEMETHOD(clknode_init, prci_clk_div_init),
  310. CLKNODEMETHOD(clknode_recalc_freq, prci_clk_div_recalc),
  311. CLKNODEMETHOD_END
  312. };
  313. DEFINE_CLASS_1(prci_clk_div_clknode, prci_clk_div_clknode_class,
  314. prci_clk_div_clknode_methods, sizeof(struct prci_clk_div_sc),
  315. clknode_class);
  316. static int
  317. prci_probe(device_t dev)
  318. {
  319. if (!ofw_bus_status_okay(dev))
  320. return (ENXIO);
  321. if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  322. return (ENXIO);
  323. device_set_desc(dev, "SiFive Power Reset Clocking Interrupt");
  324. return (BUS_PROBE_DEFAULT);
  325. }
  326. static void
  327. prci_pll_register(struct prci_softc *parent_sc, struct clknode_init_def *clkdef,
  328. uint32_t reg)
  329. {
  330. struct clknode *clk;
  331. struct prci_clk_pll_sc *sc;
  332. clk = clknode_create(parent_sc->clkdom, &prci_clk_pll_clknode_class,
  333. clkdef);
  334. if (clk == NULL)
  335. panic("Failed to create clknode");
  336. sc = clknode_get_softc(clk);
  337. sc->parent_sc = parent_sc;
  338. sc->reg = reg;
  339. clknode_register(parent_sc->clkdom, clk);
  340. }
  341. static void
  342. prci_div_register(struct prci_softc *parent_sc, struct clknode_init_def *clkdef,
  343. uint32_t reg, uint32_t bias)
  344. {
  345. struct clknode *clk;
  346. struct prci_clk_div_sc *sc;
  347. clk = clknode_create(parent_sc->clkdom, &prci_clk_div_clknode_class,
  348. clkdef);
  349. if (clk == NULL)
  350. panic("Failed to create clknode");
  351. sc = clknode_get_softc(clk);
  352. sc->parent_sc = parent_sc;
  353. sc->reg = reg;
  354. sc->bias = bias;
  355. clknode_register(parent_sc->clkdom, clk);
  356. }
  357. static int
  358. prci_attach(device_t dev)
  359. {
  360. struct clknode_init_def clkdef, clkdef_div;
  361. struct clk_gate_def clkdef_gate;
  362. struct prci_softc *sc;
  363. clk_t clk_parent;
  364. phandle_t node;
  365. int i, ncells, error;
  366. struct prci_config *cfg;
  367. struct prci_pll_def *pll_clk;
  368. struct prci_div_def *div_clk;
  369. struct prci_gate_def *gate_clk;
  370. sc = device_get_softc(dev);
  371. sc->dev = dev;
  372. cfg = (struct prci_config *)ofw_bus_search_compatible(dev,
  373. compat_data)->ocd_data;
  374. mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF);
  375. error = bus_alloc_resources(dev, prci_spec, &sc->res);
  376. if (error) {
  377. device_printf(dev, "Couldn't allocate resources\n");
  378. goto fail;
  379. }
  380. sc->bst = rman_get_bustag(sc->res);
  381. sc->bsh = rman_get_bushandle(sc->res);
  382. node = ofw_bus_get_node(dev);
  383. error = ofw_bus_parse_xref_list_get_length(node, "clocks",
  384. "#clock-cells", &ncells);
  385. if (error != 0 || ncells < 1) {
  386. device_printf(dev, "couldn't find parent clock\n");
  387. goto fail;
  388. }
  389. bzero(&clkdef, sizeof(clkdef));
  390. clkdef.parent_names = mallocarray(ncells, sizeof(char *), M_OFWPROP,
  391. M_WAITOK);
  392. for (i = 0; i < ncells; i++) {
  393. error = clk_get_by_ofw_index(dev, 0, i, &clk_parent);
  394. if (error != 0) {
  395. device_printf(dev, "cannot get clock %d\n", error);
  396. goto fail1;
  397. }
  398. clkdef.parent_names[i] = clk_get_name(clk_parent);
  399. if (bootverbose)
  400. device_printf(dev, "clk parent: %s\n",
  401. clkdef.parent_names[i]);
  402. clk_release(clk_parent);
  403. }
  404. clkdef.parent_cnt = ncells;
  405. sc->clkdom = clkdom_create(dev);
  406. if (sc->clkdom == NULL) {
  407. device_printf(dev, "Couldn't create clock domain\n");
  408. goto fail;
  409. }
  410. /* We can't free a clkdom, so from now on we cannot fail. */
  411. for (pll_clk = cfg->pll_clks; pll_clk->name; pll_clk++) {
  412. clkdef.id = pll_clk->id;
  413. clkdef.name = pll_clk->name;
  414. prci_pll_register(sc, &clkdef, pll_clk->reg);
  415. }
  416. if (cfg->div_clks != NULL) {
  417. bzero(&clkdef_div, sizeof(clkdef_div));
  418. for (div_clk = cfg->div_clks; div_clk->name; div_clk++) {
  419. clkdef_div.id = div_clk->id;
  420. clkdef_div.name = div_clk->name;
  421. clkdef_div.parent_names = &div_clk->parent_name;
  422. clkdef_div.parent_cnt = 1;
  423. prci_div_register(sc, &clkdef_div, div_clk->reg,
  424. div_clk->bias);
  425. }
  426. }
  427. if (cfg->gate_clks != NULL) {
  428. bzero(&clkdef_gate, sizeof(clkdef_gate));
  429. for (gate_clk = cfg->gate_clks; gate_clk->name; gate_clk++) {
  430. clkdef_gate.clkdef.id = gate_clk->id;
  431. clkdef_gate.clkdef.name = gate_clk->name;
  432. clkdef_gate.clkdef.parent_names = &gate_clk->parent_name;
  433. clkdef_gate.clkdef.parent_cnt = 1;
  434. clkdef_gate.offset = gate_clk->reg;
  435. clkdef_gate.shift = 0;
  436. clkdef_gate.mask = 1;
  437. clkdef_gate.on_value = 1;
  438. clkdef_gate.off_value = 0;
  439. error = clknode_gate_register(sc->clkdom,
  440. &clkdef_gate);
  441. if (error != 0) {
  442. device_printf(dev,
  443. "Couldn't create gated clock %s: %d\n",
  444. gate_clk->name, error);
  445. goto fail;
  446. }
  447. }
  448. }
  449. /*
  450. * Register the fixed clock "tlclk".
  451. *
  452. * If an older device tree is being used, tlclk may appear as its own
  453. * entity in the device tree, under soc/tlclk. If this is the case it
  454. * will be registered automatically by the fixed_clk driver, and the
  455. * version we register here will be an unreferenced duplicate.
  456. */
  457. clknode_fixed_register(sc->clkdom, cfg->tlclk_def);
  458. error = clkdom_finit(sc->clkdom);
  459. if (error)
  460. panic("Couldn't finalise clock domain");
  461. sc->nresets = cfg->nresets;
  462. return (0);
  463. fail1:
  464. free(clkdef.parent_names, M_OFWPROP);
  465. fail:
  466. bus_release_resources(dev, prci_spec, &sc->res);
  467. mtx_destroy(&sc->mtx);
  468. return (error);
  469. }
  470. static int
  471. prci_write_4(device_t dev, bus_addr_t addr, uint32_t val)
  472. {
  473. struct prci_softc *sc;
  474. sc = device_get_softc(dev);
  475. PRCI_WRITE(sc, addr, val);
  476. return (0);
  477. }
  478. static int
  479. prci_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
  480. {
  481. struct prci_softc *sc;
  482. sc = device_get_softc(dev);
  483. *val = PRCI_READ(sc, addr);
  484. return (0);
  485. }
  486. static int
  487. prci_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
  488. {
  489. struct prci_softc *sc;
  490. uint32_t reg;
  491. sc = device_get_softc(dev);
  492. reg = PRCI_READ(sc, addr);
  493. reg &= ~clr;
  494. reg |= set;
  495. PRCI_WRITE(sc, addr, reg);
  496. return (0);
  497. }
  498. static void
  499. prci_device_lock(device_t dev)
  500. {
  501. struct prci_softc *sc;
  502. sc = device_get_softc(dev);
  503. PRCI_LOCK(sc);
  504. }
  505. static void
  506. prci_device_unlock(device_t dev)
  507. {
  508. struct prci_softc *sc;
  509. sc = device_get_softc(dev);
  510. PRCI_UNLOCK(sc);
  511. }
  512. static int
  513. prci_reset_assert(device_t dev, intptr_t id, bool reset)
  514. {
  515. struct prci_softc *sc;
  516. uint32_t reg;
  517. sc = device_get_softc(dev);
  518. if (id >= sc->nresets)
  519. return (ENXIO);
  520. PRCI_LOCK(sc);
  521. reg = PRCI_READ(sc, PRCI_DEVICES_RESET_N);
  522. if (reset)
  523. reg &= ~(1u << id);
  524. else
  525. reg |= (1u << id);
  526. PRCI_WRITE(sc, PRCI_DEVICES_RESET_N, reg);
  527. PRCI_UNLOCK(sc);
  528. return (0);
  529. }
  530. static int
  531. prci_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
  532. {
  533. struct prci_softc *sc;
  534. uint32_t reg;
  535. sc = device_get_softc(dev);
  536. if (id >= sc->nresets)
  537. return (ENXIO);
  538. PRCI_LOCK(sc);
  539. reg = PRCI_READ(sc, PRCI_DEVICES_RESET_N);
  540. *reset = (reg & (1u << id)) == 0;
  541. PRCI_UNLOCK(sc);
  542. return (0);
  543. }
  544. static device_method_t prci_methods[] = {
  545. DEVMETHOD(device_probe, prci_probe),
  546. DEVMETHOD(device_attach, prci_attach),
  547. /* clkdev interface */
  548. DEVMETHOD(clkdev_write_4, prci_write_4),
  549. DEVMETHOD(clkdev_read_4, prci_read_4),
  550. DEVMETHOD(clkdev_modify_4, prci_modify_4),
  551. DEVMETHOD(clkdev_device_lock, prci_device_lock),
  552. DEVMETHOD(clkdev_device_unlock, prci_device_unlock),
  553. /* Reset interface */
  554. DEVMETHOD(hwreset_assert, prci_reset_assert),
  555. DEVMETHOD(hwreset_is_asserted, prci_reset_is_asserted),
  556. DEVMETHOD_END
  557. };
  558. static driver_t prci_driver = {
  559. "sifive_prci",
  560. prci_methods,
  561. sizeof(struct prci_softc)
  562. };
  563. /*
  564. * hfclk and rtcclk appear later in the device tree than prci, so we must
  565. * attach late.
  566. */
  567. EARLY_DRIVER_MODULE(sifive_prci, simplebus, prci_driver, 0, 0,
  568. BUS_PASS_BUS + BUS_PASS_ORDER_LATE);