1215976Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215976Sjmallett * reserved.
4215976Sjmallett *
5215976Sjmallett *
6215976Sjmallett * Redistribution and use in source and binary forms, with or without
7215976Sjmallett * modification, are permitted provided that the following conditions are
8215976Sjmallett * met:
9215976Sjmallett *
10215976Sjmallett *   * Redistributions of source code must retain the above copyright
11215976Sjmallett *     notice, this list of conditions and the following disclaimer.
12215976Sjmallett *
13215976Sjmallett *   * Redistributions in binary form must reproduce the above
14215976Sjmallett *     copyright notice, this list of conditions and the following
15215976Sjmallett *     disclaimer in the documentation and/or other materials provided
16215976Sjmallett *     with the distribution.
17215976Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215976Sjmallett *     its contributors may be used to endorse or promote products
20215976Sjmallett *     derived from this software without specific prior written
21215976Sjmallett *     permission.
22215976Sjmallett
23215976Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215976Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215976Sjmallett * regulations, and may be subject to export or import  regulations in other
26215976Sjmallett * countries.
27215976Sjmallett
28215976Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215976Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215976Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215976Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215976Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215976Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215976Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215976Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215976Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38215976Sjmallett ***********************license end**************************************/
39215976Sjmallett
40215976Sjmallett/**
41215976Sjmallett * @file
42215976Sjmallett *
43215976Sjmallett * Interface to power-throttle control, measurement, and debugging
44215976Sjmallett * facilities.
45215976Sjmallett *
46232812Sjmallett * <hr>$Revision: 70030 $<hr>
47215976Sjmallett *
48215976Sjmallett */
49215976Sjmallett
50215976Sjmallett#include "cvmx.h"
51215976Sjmallett#include "cvmx-asm.h"
52232812Sjmallett#include "cvmx-coremask.h"
53215976Sjmallett#include "cvmx-power-throttle.h"
54215976Sjmallett
55215976Sjmallett
56232812Sjmallett#define CVMX_PTH_GET_MASK(len, pos)	\
57232812Sjmallett	((((uint64_t)1 << (len)) - 1) << (pos))
58232812Sjmallett
59232812Sjmallett#define CVMX_PTH_AVAILABLE		\
60232812Sjmallett    (cvmx_power_throttle_get_register(0) != (uint64_t)-1)
61232812Sjmallett
62215976Sjmallett/**
63232812Sjmallett * a field of the POWTHROTTLE register
64232812Sjmallett */
65232812Sjmallettstatic struct cvmx_power_throttle_rfield_t {
66232812Sjmallett	char	name[16];	/* the field's name */
67232812Sjmallett	int32_t	pos;		/* position of the field's LSb */
68232812Sjmallett	int32_t	len;		/* the field's length */
69232812Sjmallett	int	present;	/* 1 for present */
70232812Sjmallett} cvmx_power_throttle_rfield[] = {
71232812Sjmallett	{"MAXPOW",   56,  8, 0},
72232812Sjmallett	{"POWER" ,   48,  8, 0},
73232812Sjmallett	{"THROTT",   40,  8, 0},
74232812Sjmallett	{"Reserved", 28, 12, 0},
75232812Sjmallett	{"DISTAG",   27,  1, 0},
76232812Sjmallett	{"PERIOD",   24,  3, 0},
77232812Sjmallett	{"POWLIM",   16,  8, 0},
78232812Sjmallett	{"MAXTHR",    8,  8, 0},
79232812Sjmallett	{"MINTHR",    0,  8, 0},
80232812Sjmallett	{"HRMPOWADJ",32,  8, 0},
81232812Sjmallett	{"OVRRD",    28,  1, 0}
82232812Sjmallett};
83232812Sjmallett
84232812Sjmallettstatic uint64_t cvmx_power_throttle_csr_addr(int ppid);
85232812Sjmallett
86232812Sjmallettstatic int cvmx_power_throttle_initialized;
87232812Sjmallett
88232812Sjmallett/**
89215976Sjmallett * @INTERNAL
90232812Sjmallett * Initialize cvmx_power_throttle_rfield[] based on model.
91232812Sjmallett */
92232812Sjmallettstatic void cvmx_power_throttle_init(void)
93232812Sjmallett{
94232812Sjmallett    /*
95232812Sjmallett     * Turn on the fields for a model
96232812Sjmallett     */
97232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
98232812Sjmallett    {
99232812Sjmallett        int i;
100232812Sjmallett	struct cvmx_power_throttle_rfield_t *p;
101232812Sjmallett
102232812Sjmallett        for (i = 0; i < CVMX_PTH_INDEX_MAX; i++)
103232812Sjmallett	    cvmx_power_throttle_rfield[i].present = 1;
104232812Sjmallett
105232812Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN63XX))
106232812Sjmallett	{
107232812Sjmallett	    /*
108232812Sjmallett	     * These fields do not come with o63
109232812Sjmallett	     */
110232812Sjmallett	    p = &cvmx_power_throttle_rfield[CVMX_PTH_INDEX_HRMPOWADJ];
111232812Sjmallett	    p->present = 0;
112232812Sjmallett	    p = &cvmx_power_throttle_rfield[CVMX_PTH_INDEX_OVRRD];
113232812Sjmallett	    p->present = 0;
114232812Sjmallett	}
115232812Sjmallett	else
116232812Sjmallett	{
117232812Sjmallett	    /*
118232812Sjmallett	     * The reserved field shrinks in models newer than o63
119232812Sjmallett	     */
120232812Sjmallett	    p = &cvmx_power_throttle_rfield[CVMX_PTH_INDEX_RESERVED];
121232812Sjmallett	    p->pos = 29;
122232812Sjmallett	    p->len = 3;
123232812Sjmallett	}
124232812Sjmallett    }
125232812Sjmallett}
126232812Sjmallett
127232812Sjmallettuint64_t cvmx_power_throttle_get_field(uint64_t r,
128232812Sjmallett    cvmx_power_throttle_field_index_t i)
129232812Sjmallett{
130232812Sjmallett    uint64_t m;
131232812Sjmallett    struct cvmx_power_throttle_rfield_t *p;
132232812Sjmallett
133232812Sjmallett    assert(i < CVMX_PTH_INDEX_MAX);
134232812Sjmallett    p = &cvmx_power_throttle_rfield[i];
135232812Sjmallett    if (!p->present)
136232812Sjmallett        return (uint64_t) -1;
137232812Sjmallett    m = CVMX_PTH_GET_MASK(p->len, p->pos);
138232812Sjmallett
139232812Sjmallett    return((r & m) >> p->pos);
140232812Sjmallett}
141232812Sjmallett
142232812Sjmallett/**
143232812Sjmallett * @INTERNAL
144232812Sjmallett * Set the i'th field of power-throttle register r to v.
145232812Sjmallett */
146232812Sjmallettstatic int cvmx_power_throttle_set_field(int i, uint64_t r, uint64_t v)
147232812Sjmallett{
148232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
149232812Sjmallett    {
150232812Sjmallett        uint64_t m;
151232812Sjmallett        struct cvmx_power_throttle_rfield_t *p;
152232812Sjmallett
153232812Sjmallett        assert(i < CVMX_PTH_INDEX_MAX);
154232812Sjmallett
155232812Sjmallett        p = &cvmx_power_throttle_rfield[i];
156232812Sjmallett        m = CVMX_PTH_GET_MASK(p->len, p->pos);
157232812Sjmallett
158232812Sjmallett        return((~m & r) | ((v << p->pos) & m));
159232812Sjmallett    }
160232812Sjmallett    return 0;
161232812Sjmallett}
162232812Sjmallett
163232812Sjmallett/**
164232812Sjmallett * @INTERNAL
165215976Sjmallett * Set the POWLIM field as percentage% of the MAXPOW field in r.
166215976Sjmallett */
167232812Sjmallettstatic uint64_t cvmx_power_throttle_set_powlim(int ppid,
168232812Sjmallett    uint8_t percentage)
169215976Sjmallett{
170215976Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
171215976Sjmallett    {
172232812Sjmallett        uint64_t t, csr_addr, r;
173215976Sjmallett
174215976Sjmallett        assert(percentage < 101);
175232812Sjmallett        csr_addr = cvmx_power_throttle_csr_addr(ppid);
176232812Sjmallett        r = cvmx_read_csr(csr_addr);
177232812Sjmallett
178232812Sjmallett        t = cvmx_power_throttle_get_field(r, CVMX_PTH_INDEX_MAXPOW);
179232812Sjmallett	if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
180232812Sjmallett	{
181232812Sjmallett	    uint64_t s;
182232812Sjmallett
183232812Sjmallett	    s = cvmx_power_throttle_get_field(r, CVMX_PTH_INDEX_HRMPOWADJ);
184232812Sjmallett	    assert(t > s);
185232812Sjmallett	    t = t - s;
186232812Sjmallett	}
187232812Sjmallett
188232812Sjmallett	t = percentage * t / 100;
189215976Sjmallett        r = cvmx_power_throttle_set_field(CVMX_PTH_INDEX_POWLIM, r, t);
190215976Sjmallett
191232812Sjmallett        cvmx_write_csr(csr_addr, r);
192215976Sjmallett        return r;
193215976Sjmallett    }
194215976Sjmallett    return 0;
195215976Sjmallett}
196215976Sjmallett
197215976Sjmallett/**
198215976Sjmallett * @INTERNAL
199215976Sjmallett * Given ppid, calculate its PowThrottle register's L2C_COP0_MAP CSR
200215976Sjmallett * address. (ppid == PTH_PPID_BCAST is for broadcasting)
201215976Sjmallett */
202232812Sjmallettstatic uint64_t cvmx_power_throttle_csr_addr(int ppid)
203215976Sjmallett{
204215976Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
205215976Sjmallett    {
206215976Sjmallett        uint64_t csr_addr, reg_num, reg_reg, reg_sel;
207215976Sjmallett
208232812Sjmallett        assert(ppid < CVMX_MAX_CORES);
209232812Sjmallett
210215976Sjmallett        /*
211215976Sjmallett         * register 11 selection 6
212215976Sjmallett         */
213215976Sjmallett        reg_reg = 11;
214215976Sjmallett        reg_sel = 6;
215215976Sjmallett        reg_num = (ppid << 8) + (reg_reg << 3) + reg_sel;
216215976Sjmallett        csr_addr = CVMX_L2C_COP0_MAPX(0) + ((reg_num) << 3);
217215976Sjmallett
218215976Sjmallett        return csr_addr;
219215976Sjmallett    }
220215976Sjmallett    return 0;
221215976Sjmallett}
222215976Sjmallett
223215976Sjmallettint cvmx_power_throttle_self(uint8_t percentage)
224215976Sjmallett{
225232812Sjmallett    if (!CVMX_PTH_AVAILABLE)
226232812Sjmallett        return -1;
227215976Sjmallett
228232812Sjmallett    if (cvmx_power_throttle_set_powlim(cvmx_get_core_num(),
229232812Sjmallett        percentage) == 0)
230232812Sjmallett	return -1;
231215976Sjmallett
232215976Sjmallett    return 0;
233215976Sjmallett}
234215976Sjmallett
235215976Sjmallettint cvmx_power_throttle(uint8_t percentage, uint64_t coremask)
236215976Sjmallett{
237232812Sjmallett    int ppid;
238232812Sjmallett    int ret;
239232812Sjmallett
240232812Sjmallett    if (!CVMX_PTH_AVAILABLE)
241232812Sjmallett        return -1;
242232812Sjmallett
243232812Sjmallett    ret = 0;
244232812Sjmallett    for (ppid = 0; ppid < CVMX_MAX_CORES; ppid++)
245215976Sjmallett    {
246232812Sjmallett        if ((((uint64_t) 1) << ppid) & coremask)
247232812Sjmallett	{
248232812Sjmallett            if (cvmx_power_throttle_set_powlim(ppid, percentage) == 0)
249232812Sjmallett	        ret = -2;
250215976Sjmallett        }
251215976Sjmallett    }
252215976Sjmallett
253232812Sjmallett    return ret;
254215976Sjmallett}
255232812Sjmallett
256232812Sjmallettint cvmx_power_throttle_bmp(uint8_t percentage, struct cvmx_coremask *pcm)
257232812Sjmallett{
258232812Sjmallett    int ppid;
259232812Sjmallett    int ret;
260232812Sjmallett
261232812Sjmallett    if (!CVMX_PTH_AVAILABLE)
262232812Sjmallett        return -1;
263232812Sjmallett
264232812Sjmallett    ret = 0;
265232812Sjmallett    CVMX_COREMASK_FOR_EACH_CORE_BEGIN(pcm, ppid)
266232812Sjmallett    {
267232812Sjmallett        if (cvmx_power_throttle_set_powlim(ppid, percentage) == 0)
268232812Sjmallett	    ret = -2;
269232812Sjmallett    } CVMX_COREMASK_FOR_EACH_CORE_END;
270232812Sjmallett
271232812Sjmallett    return ret;
272232812Sjmallett}
273232812Sjmallett
274232812Sjmallettuint64_t cvmx_power_throttle_get_register(int ppid)
275232812Sjmallett{
276232812Sjmallett    uint64_t csr_addr;
277232812Sjmallett
278232812Sjmallett    if (!cvmx_power_throttle_initialized)
279232812Sjmallett    {
280232812Sjmallett	cvmx_power_throttle_init();
281232812Sjmallett	cvmx_power_throttle_initialized = 1;
282232812Sjmallett    }
283232812Sjmallett
284232812Sjmallett    csr_addr = cvmx_power_throttle_csr_addr(ppid);
285232812Sjmallett
286232812Sjmallett    if (csr_addr == 0)
287232812Sjmallett        return -1;
288232812Sjmallett
289232812Sjmallett    return cvmx_read_csr(csr_addr);
290232812Sjmallett}
291