0002-gemgxl-mgmt-implement-clock-switch-for-GEM-tx_clk.patch 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. From 3d9d2c51f1c4780deafb2fcaf4c5ad14b8ae9e68 Mon Sep 17 00:00:00 2001
  2. From: "Wesley W. Terpstra" <wesley@sifive.com>
  3. Date: Tue, 6 Feb 2018 11:03:07 -0800
  4. Subject: [PATCH 02/10] gemgxl-mgmt: implement clock switch for GEM tx_clk
  5. Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
  6. ---
  7. .../bindings/clock/sifive,gemgxl-mgmt.txt | 26 ++++
  8. drivers/clk/Kconfig | 1 +
  9. drivers/clk/Makefile | 1 +
  10. drivers/clk/sifive/Kconfig | 9 ++
  11. drivers/clk/sifive/Makefile | 2 +
  12. drivers/clk/sifive/gemgxl-mgmt.c | 129 ++++++++++++++++++
  13. 6 files changed, 168 insertions(+)
  14. create mode 100644 Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt
  15. create mode 100644 drivers/clk/sifive/Kconfig
  16. create mode 100644 drivers/clk/sifive/Makefile
  17. create mode 100644 drivers/clk/sifive/gemgxl-mgmt.c
  18. diff --git a/Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt b/Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt
  19. new file mode 100644
  20. index 000000000000..349489e33eda
  21. --- /dev/null
  22. +++ b/Documentation/devicetree/bindings/clock/sifive,gemgxl-mgmt.txt
  23. @@ -0,0 +1,26 @@
  24. +TX clock switch for GEMGXL in U540 SoCs
  25. +
  26. +This binding uses the common clock binding:
  27. + Documentation/devicetree/bindings/clock/clock-bindings.txt
  28. +
  29. +The U54 includes a clock mux to control the ethernet TX frequenecy. It
  30. +switches between the local TX clock (125MHz) and PHY TX clocks. This is
  31. +necessary to toggle between 1Gb and 100/10Mb speeds.
  32. +
  33. +Required properties:
  34. +- compatible: Should be "sifive,cadencegemgxlmgmt0"
  35. +- #clock-cells: Should be <0>
  36. +- reg: Specifies base physical address and size of the registers
  37. +
  38. +Example:
  39. +
  40. + mgmt: cadence-gemgxl-mgmt@100a00000 {
  41. + compatible = "sifive,cadencegemgxlmgmt0";
  42. + #clock-cells = <0>;
  43. + reg = <0x0 0x100a0000 0x0 0x1000>;
  44. + };
  45. +
  46. + ethernet@10090000 {
  47. + ...
  48. + clocks = <&mgmt>; /* TX clock */
  49. + };
  50. diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
  51. index e705aab9e38b..49d72e084eac 100644
  52. --- a/drivers/clk/Kconfig
  53. +++ b/drivers/clk/Kconfig
  54. @@ -309,6 +309,7 @@ source "drivers/clk/mvebu/Kconfig"
  55. source "drivers/clk/qcom/Kconfig"
  56. source "drivers/clk/renesas/Kconfig"
  57. source "drivers/clk/samsung/Kconfig"
  58. +source "drivers/clk/sifive/Kconfig"
  59. source "drivers/clk/sprd/Kconfig"
  60. source "drivers/clk/sunxi-ng/Kconfig"
  61. source "drivers/clk/tegra/Kconfig"
  62. diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
  63. index 1db133652f0c..62ba714e34b1 100644
  64. --- a/drivers/clk/Makefile
  65. +++ b/drivers/clk/Makefile
  66. @@ -93,6 +93,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
  67. obj-y += renesas/
  68. obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
  69. obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
  70. +obj-y += sifive/
  71. obj-$(CONFIG_ARCH_SIRF) += sirf/
  72. obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
  73. obj-$(CONFIG_PLAT_SPEAR) += spear/
  74. diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
  75. new file mode 100644
  76. index 000000000000..284bffb121eb
  77. --- /dev/null
  78. +++ b/drivers/clk/sifive/Kconfig
  79. @@ -0,0 +1,9 @@
  80. +config CLK_U54_PRCI
  81. + bool "PRCI driver for U54 SoCs"
  82. + ---help---
  83. + Supports Power Reset Clock interface found in U540 SoCs
  84. +
  85. +config CLK_GEMGXL_MGMT
  86. + bool "TX clock switch for GEMGXL in U540 SoCs"
  87. + ---help---
  88. + Supports clock muxing between 10/100Mbit and 1Gbit TX clock on U540 SoCs
  89. diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
  90. new file mode 100644
  91. index 000000000000..7784d2ee0f44
  92. --- /dev/null
  93. +++ b/drivers/clk/sifive/Makefile
  94. @@ -0,0 +1,2 @@
  95. +obj-$(CONFIG_CLK_U54_PRCI) += u54-prci.o
  96. +obj-$(CONFIG_CLK_GEMGXL_MGMT) += gemgxl-mgmt.o
  97. diff --git a/drivers/clk/sifive/gemgxl-mgmt.c b/drivers/clk/sifive/gemgxl-mgmt.c
  98. new file mode 100644
  99. index 000000000000..00b07580fe3c
  100. --- /dev/null
  101. +++ b/drivers/clk/sifive/gemgxl-mgmt.c
  102. @@ -0,0 +1,129 @@
  103. +/*
  104. + * This program is free software; you can redistribute it and/or modify
  105. + * it under the terms of the GNU General Public License version 2 as
  106. + * published by the Free Software Foundation.
  107. + *
  108. + * This program is distributed in the hope that it will be useful,
  109. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  110. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  111. + * GNU General Public License for more details.
  112. + *
  113. + * Copyright (C) 2018 SiFive, Inc.
  114. + */
  115. +
  116. +#include <linux/clkdev.h>
  117. +#include <linux/clk-provider.h>
  118. +#include <linux/err.h>
  119. +#include <linux/of.h>
  120. +#include <linux/platform_device.h>
  121. +#include <linux/slab.h>
  122. +
  123. +struct sifive_gemgxl_mgmt {
  124. + void __iomem *reg;
  125. + unsigned long rate;
  126. + struct clk_hw hw;
  127. +};
  128. +
  129. +#define to_sifive_gemgxl_mgmt(mgmt) container_of(mgmt, struct sifive_gemgxl_mgmt, hw)
  130. +
  131. +static unsigned long sifive_gemgxl_mgmt_recalc_rate(struct clk_hw *hw,
  132. + unsigned long parent_rate)
  133. +{
  134. + struct sifive_gemgxl_mgmt *mgmt = to_sifive_gemgxl_mgmt(hw);
  135. + return mgmt->rate;
  136. +}
  137. +
  138. +static long sifive_gemgxl_mgmt_round_rate(struct clk_hw *hw, unsigned long rate,
  139. + unsigned long *parent_rate)
  140. +{
  141. + if (WARN_ON(rate < 2500000)) {
  142. + return 2500000;
  143. + } else if (rate == 2500000) {
  144. + return 2500000;
  145. + } else if (WARN_ON(rate < 13750000)) {
  146. + return 2500000;
  147. + } else if (WARN_ON(rate < 25000000)) {
  148. + return 25000000;
  149. + } else if (rate == 25000000) {
  150. + return 25000000;
  151. + } else if (WARN_ON(rate < 75000000)) {
  152. + return 25000000;
  153. + } else if (WARN_ON(rate < 125000000)) {
  154. + return 125000000;
  155. + } else if (rate == 125000000) {
  156. + return 125000000;
  157. + } else {
  158. + WARN_ON(rate > 125000000);
  159. + return 125000000;
  160. + }
  161. +}
  162. +
  163. +static int sifive_gemgxl_mgmt_set_rate(struct clk_hw *hw, unsigned long rate,
  164. + unsigned long parent_rate)
  165. +{
  166. + struct sifive_gemgxl_mgmt *mgmt = to_sifive_gemgxl_mgmt(hw);
  167. + rate = sifive_gemgxl_mgmt_round_rate(hw, rate, &parent_rate);
  168. + iowrite32(rate != 125000000, mgmt->reg);
  169. + mgmt->rate = rate;
  170. + return 0;
  171. +}
  172. +
  173. +static const struct clk_ops sifive_gemgxl_mgmt_ops = {
  174. + .recalc_rate = sifive_gemgxl_mgmt_recalc_rate,
  175. + .round_rate = sifive_gemgxl_mgmt_round_rate,
  176. + .set_rate = sifive_gemgxl_mgmt_set_rate,
  177. +};
  178. +
  179. +static int sifive_gemgxl_mgmt_probe(struct platform_device *pdev)
  180. +{
  181. + struct clk_init_data init;
  182. + struct sifive_gemgxl_mgmt *mgmt;
  183. + struct resource *res;
  184. + struct clk *clk;
  185. +
  186. + mgmt = devm_kzalloc(&pdev->dev, sizeof(*mgmt), GFP_KERNEL);
  187. + if (!mgmt)
  188. + return -ENOMEM;
  189. +
  190. + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  191. + mgmt->reg = devm_ioremap_resource(&pdev->dev, res);
  192. + if (IS_ERR(mgmt->reg))
  193. + return PTR_ERR(mgmt->reg);
  194. +
  195. + init.name = pdev->dev.of_node->name;
  196. + init.ops = &sifive_gemgxl_mgmt_ops;
  197. + init.flags = 0;
  198. + init.num_parents = 0;
  199. +
  200. + mgmt->rate = 0;
  201. + mgmt->hw.init = &init;
  202. +
  203. + clk = clk_register(NULL, &mgmt->hw);
  204. + if (IS_ERR(clk))
  205. + return PTR_ERR(clk);
  206. +
  207. + of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk);
  208. +
  209. + dev_info(&pdev->dev, "Registered clock switch '%s'\n", init.name);
  210. +
  211. + return 0;
  212. +}
  213. +
  214. +static const struct of_device_id sifive_gemgxl_mgmt_of_match[] = {
  215. + { .compatible = "sifive,cadencegemgxlmgmt0", },
  216. + {}
  217. +};
  218. +
  219. +static struct platform_driver sifive_gemgxl_mgmt_driver = {
  220. + .driver = {
  221. + .name = "sifive-gemgxl-mgmt",
  222. + .of_match_table = sifive_gemgxl_mgmt_of_match,
  223. + },
  224. + .probe = sifive_gemgxl_mgmt_probe,
  225. +};
  226. +
  227. +static int __init sifive_gemgxl_mgmt_init(void)
  228. +{
  229. + return platform_driver_register(&sifive_gemgxl_mgmt_driver);
  230. +}
  231. +core_initcall(sifive_gemgxl_mgmt_init);
  232. --
  233. 2.21.0