1 /*
2 * drivers/amlogic/media/common/arch/switch/amports_gate.c
3 *
4 * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 */
17 #define DEBUG
18 #include <linux/compiler.h>
19 #include <linux/clk-provider.h>
20 #include <linux/err.h>
21 #include <linux/kernel.h>
22 #include <linux/spinlock.h>
23 #include <linux/clk.h>
24 #include "amports_gate.h"
25 #include <linux/amlogic/media/utils/vdec_reg.h>
26 #include "../../../stream_input/amports/amports_priv.h"
27 #include "../../../frame_provider/decoder/utils/vdec.h"
28 #include "../clk/clk.h"
29
30
31 #define DEBUG_REF 1
32 #define GATE_RESET_OK
33
34 #ifdef GATE_RESET_OK
35
36 struct gate_switch_node gates[] = {
37 {
38 .name = "demux",
39 },
40 {
41 .name = "parser_top",
42 },
43 {
44 .name = "vdec",
45 },
46 {
47 .name = "clk_81",
48 },
49 {
50 .name = "clk_vdec_mux",
51 },
52 {
53 .name = "clk_hcodec_mux",
54 },
55 {
56 .name = "clk_hevc_mux",
57 },
58 {
59 .name = "clk_hevcb_mux",
60 },
61 {
62 .name = "ahbarb0",
63 },
64 {
65 .name = "asyncfifo",
66 },
67 };
68
69 /*
70 *mesonstream {
71 * compatible = "amlogic, codec, streambuf";
72 * dev_name = "mesonstream";
73 * status = "okay";
74 * clocks = <&clkc CLKID_DOS_PARSER
75 * &clkc CLKID_DEMUX
76 * &clkc CLKID_DOS
77 * &clkc CLKID_VDEC_MUX
78 * &clkc CLKID_HCODEC_MUX
79 * &clkc CLKID_HEVCF_MUX
80 * &clkc CLKID_HEVC_MUX>;
81 * clock-names = "parser_top",
82 * "demux",
83 * "vdec",
84 * "clk_vdec_mux",
85 * "clk_hcodec_mux",
86 * "clk_hevc_mux",
87 * "clk_hevcb_mux";
88 *};
89 */
90
amports_clock_gate_init(struct device * dev)91 int amports_clock_gate_init(struct device *dev)
92 {
93 int i;
94
95 for (i = 0; i < sizeof(gates) / sizeof(struct gate_switch_node); i++) {
96 gates[i].clk = devm_clk_get(dev, gates[i].name);
97 if (IS_ERR_OR_NULL(gates[i].clk)) {
98 gates[i].clk = NULL;
99 pr_info("get gate %s control failed %px\n",
100 gates[i].name,
101 gates[i].clk);
102 }
103 gates[i].ref_count = 0;
104 mutex_init(&gates[i].mutex);
105 }
106
107 set_clock_gate(gates, ARRAY_SIZE(gates));
108
109 return 0;
110 }
111 EXPORT_SYMBOL(amports_clock_gate_init);
112
amports_gate_clk(struct gate_switch_node * gate_node,int enable)113 static int amports_gate_clk(struct gate_switch_node *gate_node, int enable)
114 {
115 mutex_lock(&gate_node->mutex);
116 if (enable) {
117 if (gate_node->ref_count == 0)
118 clk_prepare_enable(gate_node->clk);
119
120 gate_node->ref_count++;
121
122 if (DEBUG_REF)
123 pr_debug("the %-15s clock on, ref cnt: %d\n",
124 gate_node->name, gate_node->ref_count);
125 } else {
126 gate_node->ref_count--;
127 if (gate_node->ref_count == 0)
128 clk_disable_unprepare(gate_node->clk);
129
130 if (DEBUG_REF)
131 pr_debug("the %-15s clock off, ref cnt: %d\n",
132 gate_node->name, gate_node->ref_count);
133 }
134 mutex_unlock(&gate_node->mutex);
135
136 return 0;
137 }
138
amports_switch_gate(const char * name,int enable)139 int amports_switch_gate(const char *name, int enable)
140 {
141 int i;
142
143 for (i = 0; i < sizeof(gates) / sizeof(struct gate_switch_node); i++) {
144 if (!strcmp(name, gates[i].name)) {
145
146 /*pr_info("openclose:%d gate %s control\n", enable,
147 * gates[i].name);
148 */
149
150 if (gates[i].clk)
151 amports_gate_clk(&gates[i], enable);
152 }
153 }
154 return 0;
155 }
156 EXPORT_SYMBOL(amports_switch_gate);
157
158 #else
159 /*
160 *can used for debug.
161 *on chip bringup.
162 */
amports_clock_gate_init(struct device * dev)163 int amports_clock_gate_init(struct device *dev)
164 {
165 static int gate_inited;
166
167 if (gate_inited)
168 return 0;
169 /*
170 *#define HHI_GCLK_MPEG0 0x1050
171 *#define HHI_GCLK_MPEG1 0x1051
172 *#define HHI_GCLK_MPEG2 0x1052
173 *#define HHI_GCLK_OTHER 0x1054
174 *#define HHI_GCLK_AO 0x1055
175 */
176 WRITE_HHI_REG_BITS(HHI_GCLK_MPEG0, 1, 1, 1);/*dos*/
177 WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 1, 25, 1);/*U_parser_top()*/
178 WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 0xff, 6, 8);/*aiu()*/
179 WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 1, 4, 1);/*demux()*/
180 WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 1, 2, 1);/*audio in()*/
181 WRITE_HHI_REG_BITS(HHI_GCLK_MPEG2, 1, 25, 1);/*VPU Interrupt*/
182 gate_inited++;
183
184
185
186 return 0;
187 }
188 EXPORT_SYMBOL(amports_clock_gate_init);
189
190
amports_switch_gate(const char * name,int enable)191 int amports_switch_gate(const char *name, int enable)
192 {
193 return 0;
194 }
195 EXPORT_SYMBOL(amports_switch_gate);
196
197 #endif
198