tegra-hsp.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. /*
  2. * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. */
  13. #include <linux/interrupt.h>
  14. #include <linux/io.h>
  15. #include <linux/mailbox_controller.h>
  16. #include <linux/of.h>
  17. #include <linux/of_device.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/slab.h>
  20. #include <dt-bindings/mailbox/tegra186-hsp.h>
  21. #define HSP_INT_DIMENSIONING 0x380
  22. #define HSP_nSM_SHIFT 0
  23. #define HSP_nSS_SHIFT 4
  24. #define HSP_nAS_SHIFT 8
  25. #define HSP_nDB_SHIFT 12
  26. #define HSP_nSI_SHIFT 16
  27. #define HSP_nINT_MASK 0xf
  28. #define HSP_DB_TRIGGER 0x0
  29. #define HSP_DB_ENABLE 0x4
  30. #define HSP_DB_RAW 0x8
  31. #define HSP_DB_PENDING 0xc
  32. #define HSP_DB_CCPLEX 1
  33. #define HSP_DB_BPMP 3
  34. #define HSP_DB_MAX 7
  35. struct tegra_hsp_channel;
  36. struct tegra_hsp;
  37. struct tegra_hsp_channel {
  38. struct tegra_hsp *hsp;
  39. struct mbox_chan *chan;
  40. void __iomem *regs;
  41. };
  42. struct tegra_hsp_doorbell {
  43. struct tegra_hsp_channel channel;
  44. struct list_head list;
  45. const char *name;
  46. unsigned int master;
  47. unsigned int index;
  48. };
  49. struct tegra_hsp_db_map {
  50. const char *name;
  51. unsigned int master;
  52. unsigned int index;
  53. };
  54. struct tegra_hsp_soc {
  55. const struct tegra_hsp_db_map *map;
  56. };
  57. struct tegra_hsp {
  58. const struct tegra_hsp_soc *soc;
  59. struct mbox_controller mbox;
  60. void __iomem *regs;
  61. unsigned int irq;
  62. unsigned int num_sm;
  63. unsigned int num_as;
  64. unsigned int num_ss;
  65. unsigned int num_db;
  66. unsigned int num_si;
  67. spinlock_t lock;
  68. struct list_head doorbells;
  69. };
  70. static inline struct tegra_hsp *
  71. to_tegra_hsp(struct mbox_controller *mbox)
  72. {
  73. return container_of(mbox, struct tegra_hsp, mbox);
  74. }
  75. static inline u32 tegra_hsp_readl(struct tegra_hsp *hsp, unsigned int offset)
  76. {
  77. return readl(hsp->regs + offset);
  78. }
  79. static inline void tegra_hsp_writel(struct tegra_hsp *hsp, u32 value,
  80. unsigned int offset)
  81. {
  82. writel(value, hsp->regs + offset);
  83. }
  84. static inline u32 tegra_hsp_channel_readl(struct tegra_hsp_channel *channel,
  85. unsigned int offset)
  86. {
  87. return readl(channel->regs + offset);
  88. }
  89. static inline void tegra_hsp_channel_writel(struct tegra_hsp_channel *channel,
  90. u32 value, unsigned int offset)
  91. {
  92. writel(value, channel->regs + offset);
  93. }
  94. static bool tegra_hsp_doorbell_can_ring(struct tegra_hsp_doorbell *db)
  95. {
  96. u32 value;
  97. value = tegra_hsp_channel_readl(&db->channel, HSP_DB_ENABLE);
  98. return (value & BIT(TEGRA_HSP_DB_MASTER_CCPLEX)) != 0;
  99. }
  100. static struct tegra_hsp_doorbell *
  101. __tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master)
  102. {
  103. struct tegra_hsp_doorbell *entry;
  104. list_for_each_entry(entry, &hsp->doorbells, list)
  105. if (entry->master == master)
  106. return entry;
  107. return NULL;
  108. }
  109. static struct tegra_hsp_doorbell *
  110. tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master)
  111. {
  112. struct tegra_hsp_doorbell *db;
  113. unsigned long flags;
  114. spin_lock_irqsave(&hsp->lock, flags);
  115. db = __tegra_hsp_doorbell_get(hsp, master);
  116. spin_unlock_irqrestore(&hsp->lock, flags);
  117. return db;
  118. }
  119. static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data)
  120. {
  121. struct tegra_hsp *hsp = data;
  122. struct tegra_hsp_doorbell *db;
  123. unsigned long master, value;
  124. db = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX);
  125. if (!db)
  126. return IRQ_NONE;
  127. value = tegra_hsp_channel_readl(&db->channel, HSP_DB_PENDING);
  128. tegra_hsp_channel_writel(&db->channel, value, HSP_DB_PENDING);
  129. spin_lock(&hsp->lock);
  130. for_each_set_bit(master, &value, hsp->mbox.num_chans) {
  131. struct tegra_hsp_doorbell *db;
  132. db = __tegra_hsp_doorbell_get(hsp, master);
  133. /*
  134. * Depending on the bootloader chain, the CCPLEX doorbell will
  135. * have some doorbells enabled, which means that requesting an
  136. * interrupt will immediately fire.
  137. *
  138. * In that case, db->channel.chan will still be NULL here and
  139. * cause a crash if not properly guarded.
  140. *
  141. * It remains to be seen if ignoring the doorbell in that case
  142. * is the correct solution.
  143. */
  144. if (db && db->channel.chan)
  145. mbox_chan_received_data(db->channel.chan, NULL);
  146. }
  147. spin_unlock(&hsp->lock);
  148. return IRQ_HANDLED;
  149. }
  150. static struct tegra_hsp_channel *
  151. tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
  152. unsigned int master, unsigned int index)
  153. {
  154. struct tegra_hsp_doorbell *db;
  155. unsigned int offset;
  156. unsigned long flags;
  157. db = kzalloc(sizeof(*db), GFP_KERNEL);
  158. if (!db)
  159. return ERR_PTR(-ENOMEM);
  160. offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16;
  161. offset += index * 0x100;
  162. db->channel.regs = hsp->regs + offset;
  163. db->channel.hsp = hsp;
  164. db->name = kstrdup_const(name, GFP_KERNEL);
  165. db->master = master;
  166. db->index = index;
  167. spin_lock_irqsave(&hsp->lock, flags);
  168. list_add_tail(&db->list, &hsp->doorbells);
  169. spin_unlock_irqrestore(&hsp->lock, flags);
  170. return &db->channel;
  171. }
  172. static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
  173. {
  174. list_del(&db->list);
  175. kfree_const(db->name);
  176. kfree(db);
  177. }
  178. static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
  179. {
  180. struct tegra_hsp_doorbell *db = chan->con_priv;
  181. tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER);
  182. return 0;
  183. }
  184. static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
  185. {
  186. struct tegra_hsp_doorbell *db = chan->con_priv;
  187. struct tegra_hsp *hsp = db->channel.hsp;
  188. struct tegra_hsp_doorbell *ccplex;
  189. unsigned long flags;
  190. u32 value;
  191. if (db->master >= hsp->mbox.num_chans) {
  192. dev_err(hsp->mbox.dev,
  193. "invalid master ID %u for HSP channel\n",
  194. db->master);
  195. return -EINVAL;
  196. }
  197. ccplex = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX);
  198. if (!ccplex)
  199. return -ENODEV;
  200. if (!tegra_hsp_doorbell_can_ring(db))
  201. return -ENODEV;
  202. spin_lock_irqsave(&hsp->lock, flags);
  203. value = tegra_hsp_channel_readl(&ccplex->channel, HSP_DB_ENABLE);
  204. value |= BIT(db->master);
  205. tegra_hsp_channel_writel(&ccplex->channel, value, HSP_DB_ENABLE);
  206. spin_unlock_irqrestore(&hsp->lock, flags);
  207. return 0;
  208. }
  209. static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
  210. {
  211. struct tegra_hsp_doorbell *db = chan->con_priv;
  212. struct tegra_hsp *hsp = db->channel.hsp;
  213. struct tegra_hsp_doorbell *ccplex;
  214. unsigned long flags;
  215. u32 value;
  216. ccplex = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX);
  217. if (!ccplex)
  218. return;
  219. spin_lock_irqsave(&hsp->lock, flags);
  220. value = tegra_hsp_channel_readl(&ccplex->channel, HSP_DB_ENABLE);
  221. value &= ~BIT(db->master);
  222. tegra_hsp_channel_writel(&ccplex->channel, value, HSP_DB_ENABLE);
  223. spin_unlock_irqrestore(&hsp->lock, flags);
  224. }
  225. static const struct mbox_chan_ops tegra_hsp_doorbell_ops = {
  226. .send_data = tegra_hsp_doorbell_send_data,
  227. .startup = tegra_hsp_doorbell_startup,
  228. .shutdown = tegra_hsp_doorbell_shutdown,
  229. };
  230. static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
  231. const struct of_phandle_args *args)
  232. {
  233. struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV);
  234. struct tegra_hsp *hsp = to_tegra_hsp(mbox);
  235. unsigned int type = args->args[0];
  236. unsigned int master = args->args[1];
  237. struct tegra_hsp_doorbell *db;
  238. struct mbox_chan *chan;
  239. unsigned long flags;
  240. unsigned int i;
  241. switch (type) {
  242. case TEGRA_HSP_MBOX_TYPE_DB:
  243. db = tegra_hsp_doorbell_get(hsp, master);
  244. if (db)
  245. channel = &db->channel;
  246. break;
  247. default:
  248. break;
  249. }
  250. if (IS_ERR(channel))
  251. return ERR_CAST(channel);
  252. spin_lock_irqsave(&hsp->lock, flags);
  253. for (i = 0; i < hsp->mbox.num_chans; i++) {
  254. chan = &hsp->mbox.chans[i];
  255. if (!chan->con_priv) {
  256. chan->con_priv = channel;
  257. channel->chan = chan;
  258. break;
  259. }
  260. chan = NULL;
  261. }
  262. spin_unlock_irqrestore(&hsp->lock, flags);
  263. return chan ?: ERR_PTR(-EBUSY);
  264. }
  265. static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
  266. {
  267. struct tegra_hsp_doorbell *db, *tmp;
  268. unsigned long flags;
  269. spin_lock_irqsave(&hsp->lock, flags);
  270. list_for_each_entry_safe(db, tmp, &hsp->doorbells, list)
  271. __tegra_hsp_doorbell_destroy(db);
  272. spin_unlock_irqrestore(&hsp->lock, flags);
  273. }
  274. static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
  275. {
  276. const struct tegra_hsp_db_map *map = hsp->soc->map;
  277. struct tegra_hsp_channel *channel;
  278. while (map->name) {
  279. channel = tegra_hsp_doorbell_create(hsp, map->name,
  280. map->master, map->index);
  281. if (IS_ERR(channel)) {
  282. tegra_hsp_remove_doorbells(hsp);
  283. return PTR_ERR(channel);
  284. }
  285. map++;
  286. }
  287. return 0;
  288. }
  289. static int tegra_hsp_probe(struct platform_device *pdev)
  290. {
  291. struct tegra_hsp *hsp;
  292. struct resource *res;
  293. u32 value;
  294. int err;
  295. hsp = devm_kzalloc(&pdev->dev, sizeof(*hsp), GFP_KERNEL);
  296. if (!hsp)
  297. return -ENOMEM;
  298. hsp->soc = of_device_get_match_data(&pdev->dev);
  299. INIT_LIST_HEAD(&hsp->doorbells);
  300. spin_lock_init(&hsp->lock);
  301. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  302. hsp->regs = devm_ioremap_resource(&pdev->dev, res);
  303. if (IS_ERR(hsp->regs))
  304. return PTR_ERR(hsp->regs);
  305. value = tegra_hsp_readl(hsp, HSP_INT_DIMENSIONING);
  306. hsp->num_sm = (value >> HSP_nSM_SHIFT) & HSP_nINT_MASK;
  307. hsp->num_ss = (value >> HSP_nSS_SHIFT) & HSP_nINT_MASK;
  308. hsp->num_as = (value >> HSP_nAS_SHIFT) & HSP_nINT_MASK;
  309. hsp->num_db = (value >> HSP_nDB_SHIFT) & HSP_nINT_MASK;
  310. hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
  311. err = platform_get_irq_byname(pdev, "doorbell");
  312. if (err < 0) {
  313. dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err);
  314. return err;
  315. }
  316. hsp->irq = err;
  317. hsp->mbox.of_xlate = of_tegra_hsp_xlate;
  318. hsp->mbox.num_chans = 32;
  319. hsp->mbox.dev = &pdev->dev;
  320. hsp->mbox.txdone_irq = false;
  321. hsp->mbox.txdone_poll = false;
  322. hsp->mbox.ops = &tegra_hsp_doorbell_ops;
  323. hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
  324. sizeof(*hsp->mbox.chans),
  325. GFP_KERNEL);
  326. if (!hsp->mbox.chans)
  327. return -ENOMEM;
  328. err = tegra_hsp_add_doorbells(hsp);
  329. if (err < 0) {
  330. dev_err(&pdev->dev, "failed to add doorbells: %d\n", err);
  331. return err;
  332. }
  333. platform_set_drvdata(pdev, hsp);
  334. err = mbox_controller_register(&hsp->mbox);
  335. if (err) {
  336. dev_err(&pdev->dev, "failed to register mailbox: %d\n", err);
  337. tegra_hsp_remove_doorbells(hsp);
  338. return err;
  339. }
  340. err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq,
  341. IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp);
  342. if (err < 0) {
  343. dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
  344. hsp->irq, err);
  345. return err;
  346. }
  347. return 0;
  348. }
  349. static int tegra_hsp_remove(struct platform_device *pdev)
  350. {
  351. struct tegra_hsp *hsp = platform_get_drvdata(pdev);
  352. mbox_controller_unregister(&hsp->mbox);
  353. tegra_hsp_remove_doorbells(hsp);
  354. return 0;
  355. }
  356. static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = {
  357. { "ccplex", TEGRA_HSP_DB_MASTER_CCPLEX, HSP_DB_CCPLEX, },
  358. { "bpmp", TEGRA_HSP_DB_MASTER_BPMP, HSP_DB_BPMP, },
  359. { /* sentinel */ }
  360. };
  361. static const struct tegra_hsp_soc tegra186_hsp_soc = {
  362. .map = tegra186_hsp_db_map,
  363. };
  364. static const struct of_device_id tegra_hsp_match[] = {
  365. { .compatible = "nvidia,tegra186-hsp", .data = &tegra186_hsp_soc },
  366. { }
  367. };
  368. static struct platform_driver tegra_hsp_driver = {
  369. .driver = {
  370. .name = "tegra-hsp",
  371. .of_match_table = tegra_hsp_match,
  372. },
  373. .probe = tegra_hsp_probe,
  374. .remove = tegra_hsp_remove,
  375. };
  376. static int __init tegra_hsp_init(void)
  377. {
  378. return platform_driver_register(&tegra_hsp_driver);
  379. }
  380. core_initcall(tegra_hsp_init);