rpc-if.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Linux driver for RPC-IF HyperFlash
  4. *
  5. * Copyright (C) 2019-2020 Cogent Embedded, Inc.
  6. */
  7. #include <linux/err.h>
  8. #include <linux/kernel.h>
  9. #include <linux/module.h>
  10. #include <linux/mtd/hyperbus.h>
  11. #include <linux/mtd/mtd.h>
  12. #include <linux/mux/consumer.h>
  13. #include <linux/of.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/types.h>
  16. #include <memory/renesas-rpc-if.h>
  17. struct rpcif_hyperbus {
  18. struct rpcif rpc;
  19. struct hyperbus_ctlr ctlr;
  20. struct hyperbus_device hbdev;
  21. };
  22. static const struct rpcif_op rpcif_op_tmpl = {
  23. .cmd = {
  24. .buswidth = 8,
  25. .ddr = true,
  26. },
  27. .ocmd = {
  28. .buswidth = 8,
  29. .ddr = true,
  30. },
  31. .addr = {
  32. .nbytes = 1,
  33. .buswidth = 8,
  34. .ddr = true,
  35. },
  36. .data = {
  37. .buswidth = 8,
  38. .ddr = true,
  39. },
  40. };
  41. static void rpcif_hb_prepare_read(struct rpcif *rpc, void *to,
  42. unsigned long from, ssize_t len)
  43. {
  44. struct rpcif_op op = rpcif_op_tmpl;
  45. op.cmd.opcode = HYPERBUS_RW_READ | HYPERBUS_AS_MEM;
  46. op.addr.val = from >> 1;
  47. op.dummy.buswidth = 1;
  48. op.dummy.ncycles = 15;
  49. op.data.dir = RPCIF_DATA_IN;
  50. op.data.nbytes = len;
  51. op.data.buf.in = to;
  52. rpcif_prepare(rpc, &op, NULL, NULL);
  53. }
  54. static void rpcif_hb_prepare_write(struct rpcif *rpc, unsigned long to,
  55. void *from, ssize_t len)
  56. {
  57. struct rpcif_op op = rpcif_op_tmpl;
  58. op.cmd.opcode = HYPERBUS_RW_WRITE | HYPERBUS_AS_MEM;
  59. op.addr.val = to >> 1;
  60. op.data.dir = RPCIF_DATA_OUT;
  61. op.data.nbytes = len;
  62. op.data.buf.out = from;
  63. rpcif_prepare(rpc, &op, NULL, NULL);
  64. }
  65. static u16 rpcif_hb_read16(struct hyperbus_device *hbdev, unsigned long addr)
  66. {
  67. struct rpcif_hyperbus *hyperbus =
  68. container_of(hbdev, struct rpcif_hyperbus, hbdev);
  69. map_word data;
  70. rpcif_hb_prepare_read(&hyperbus->rpc, &data, addr, 2);
  71. rpcif_manual_xfer(&hyperbus->rpc);
  72. return data.x[0];
  73. }
  74. static void rpcif_hb_write16(struct hyperbus_device *hbdev, unsigned long addr,
  75. u16 data)
  76. {
  77. struct rpcif_hyperbus *hyperbus =
  78. container_of(hbdev, struct rpcif_hyperbus, hbdev);
  79. rpcif_hb_prepare_write(&hyperbus->rpc, addr, &data, 2);
  80. rpcif_manual_xfer(&hyperbus->rpc);
  81. }
  82. static void rpcif_hb_copy_from(struct hyperbus_device *hbdev, void *to,
  83. unsigned long from, ssize_t len)
  84. {
  85. struct rpcif_hyperbus *hyperbus =
  86. container_of(hbdev, struct rpcif_hyperbus, hbdev);
  87. rpcif_hb_prepare_read(&hyperbus->rpc, to, from, len);
  88. rpcif_dirmap_read(&hyperbus->rpc, from, len, to);
  89. }
  90. static const struct hyperbus_ops rpcif_hb_ops = {
  91. .read16 = rpcif_hb_read16,
  92. .write16 = rpcif_hb_write16,
  93. .copy_from = rpcif_hb_copy_from,
  94. };
  95. static int rpcif_hb_probe(struct platform_device *pdev)
  96. {
  97. struct device *dev = &pdev->dev;
  98. struct rpcif_hyperbus *hyperbus;
  99. int error;
  100. hyperbus = devm_kzalloc(dev, sizeof(*hyperbus), GFP_KERNEL);
  101. if (!hyperbus)
  102. return -ENOMEM;
  103. error = rpcif_sw_init(&hyperbus->rpc, pdev->dev.parent);
  104. if (error)
  105. return error;
  106. platform_set_drvdata(pdev, hyperbus);
  107. rpcif_enable_rpm(&hyperbus->rpc);
  108. rpcif_hw_init(&hyperbus->rpc, true);
  109. hyperbus->hbdev.map.size = hyperbus->rpc.size;
  110. hyperbus->hbdev.map.virt = hyperbus->rpc.dirmap;
  111. hyperbus->ctlr.dev = dev;
  112. hyperbus->ctlr.ops = &rpcif_hb_ops;
  113. hyperbus->hbdev.ctlr = &hyperbus->ctlr;
  114. hyperbus->hbdev.np = of_get_next_child(pdev->dev.parent->of_node, NULL);
  115. error = hyperbus_register_device(&hyperbus->hbdev);
  116. if (error)
  117. rpcif_disable_rpm(&hyperbus->rpc);
  118. return error;
  119. }
  120. static int rpcif_hb_remove(struct platform_device *pdev)
  121. {
  122. struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev);
  123. int error = hyperbus_unregister_device(&hyperbus->hbdev);
  124. rpcif_disable_rpm(&hyperbus->rpc);
  125. return error;
  126. }
  127. static struct platform_driver rpcif_platform_driver = {
  128. .probe = rpcif_hb_probe,
  129. .remove = rpcif_hb_remove,
  130. .driver = {
  131. .name = "rpc-if-hyperflash",
  132. },
  133. };
  134. module_platform_driver(rpcif_platform_driver);
  135. MODULE_DESCRIPTION("Renesas RPC-IF HyperFlash driver");
  136. MODULE_LICENSE("GPL v2");