clk-a20-gmac.c (3197B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright 2013 Emilio López 4 * Emilio López <emilio@elopez.com.ar> 5 * 6 * Copyright 2013 Chen-Yu Tsai 7 * Chen-Yu Tsai <wens@csie.org> 8 */ 9 10#include <linux/clk-provider.h> 11#include <linux/io.h> 12#include <linux/of.h> 13#include <linux/of_address.h> 14#include <linux/slab.h> 15 16static DEFINE_SPINLOCK(gmac_lock); 17 18/** 19 * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module 20 * 21 * This clock looks something like this 22 * ________________________ 23 * MII TX clock from PHY >-----|___________ _________|----> to GMAC core 24 * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY 25 * Ext. 125MHz RGMII TX clk >--|__divider__/ | 26 * |________________________| 27 * 28 * The external 125 MHz reference is optional, i.e. GMAC can use its 29 * internal TX clock just fine. The A31 GMAC clock module does not have 30 * the divider controls for the external reference. 31 * 32 * To keep it simple, let the GMAC use either the MII TX clock for MII mode, 33 * and its internal TX clock for GMII and RGMII modes. The GMAC driver should 34 * select the appropriate source and gate/ungate the output to the PHY. 35 * 36 * Only the GMAC should use this clock. Altering the clock so that it doesn't 37 * match the GMAC's operation parameters will result in the GMAC not being 38 * able to send traffic out. The GMAC driver should set the clock rate and 39 * enable/disable this clock to configure the required state. The clock 40 * driver then responds by auto-reparenting the clock. 41 */ 42 43#define SUN7I_A20_GMAC_GPIT 2 44#define SUN7I_A20_GMAC_MASK 0x3 45#define SUN7I_A20_GMAC_PARENTS 2 46 47static u32 sun7i_a20_gmac_mux_table[SUN7I_A20_GMAC_PARENTS] = { 48 0x00, /* Select mii_phy_tx_clk */ 49 0x02, /* Select gmac_int_tx_clk */ 50}; 51 52static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) 53{ 54 struct clk *clk; 55 struct clk_mux *mux; 56 struct clk_gate *gate; 57 const char *clk_name = node->name; 58 const char *parents[SUN7I_A20_GMAC_PARENTS]; 59 void __iomem *reg; 60 61 if (of_property_read_string(node, "clock-output-names", &clk_name)) 62 return; 63 64 /* allocate mux and gate clock structs */ 65 mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); 66 if (!mux) 67 return; 68 69 gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); 70 if (!gate) 71 goto free_mux; 72 73 /* gmac clock requires exactly 2 parents */ 74 if (of_clk_parent_fill(node, parents, 2) != 2) 75 goto free_gate; 76 77 reg = of_iomap(node, 0); 78 if (!reg) 79 goto free_gate; 80 81 /* set up gate and fixed rate properties */ 82 gate->reg = reg; 83 gate->bit_idx = SUN7I_A20_GMAC_GPIT; 84 gate->lock = &gmac_lock; 85 mux->reg = reg; 86 mux->mask = SUN7I_A20_GMAC_MASK; 87 mux->table = sun7i_a20_gmac_mux_table; 88 mux->lock = &gmac_lock; 89 90 clk = clk_register_composite(NULL, clk_name, 91 parents, SUN7I_A20_GMAC_PARENTS, 92 &mux->hw, &clk_mux_ops, 93 NULL, NULL, 94 &gate->hw, &clk_gate_ops, 95 0); 96 97 if (IS_ERR(clk)) 98 goto iounmap_reg; 99 100 of_clk_add_provider(node, of_clk_src_simple_get, clk); 101 102 return; 103 104iounmap_reg: 105 iounmap(reg); 106free_gate: 107 kfree(gate); 108free_mux: 109 kfree(mux); 110} 111CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk", 112 sun7i_a20_gmac_clk_setup);