ti_cpufreq.c revision 1.4
11.4Sthorpej/* $NetBSD: ti_cpufreq.c,v 1.4 2021/01/27 03:10:20 thorpej Exp $ */
21.1Sjmcneill
31.1Sjmcneill/*-
41.1Sjmcneill * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca>
51.1Sjmcneill * All rights reserved.
61.1Sjmcneill *
71.1Sjmcneill * Redistribution and use in source and binary forms, with or without
81.1Sjmcneill * modification, are permitted provided that the following conditions
91.1Sjmcneill * are met:
101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright
111.1Sjmcneill *    notice, this list of conditions and the following disclaimer.
121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
131.1Sjmcneill *    notice, this list of conditions and the following disclaimer in the
141.1Sjmcneill *    documentation and/or other materials provided with the distribution.
151.1Sjmcneill *
161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
171.1Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
181.1Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
191.1Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
201.1Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211.1Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
221.1Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231.1Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241.1Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251.1Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261.1Sjmcneill * SUCH DAMAGE.
271.1Sjmcneill */
281.1Sjmcneill
291.1Sjmcneill#include "opt_soc.h"
301.1Sjmcneill
311.1Sjmcneill#include <sys/cdefs.h>
321.4Sthorpej__KERNEL_RCSID(0, "$NetBSD: ti_cpufreq.c,v 1.4 2021/01/27 03:10:20 thorpej Exp $");
331.1Sjmcneill
341.1Sjmcneill#include <sys/param.h>
351.1Sjmcneill#include <sys/systm.h>
361.1Sjmcneill#include <sys/device.h>
371.1Sjmcneill#include <sys/kmem.h>
381.1Sjmcneill#include <sys/bus.h>
391.1Sjmcneill
401.1Sjmcneill#include <dev/fdt/fdtvar.h>
411.1Sjmcneill#include <dev/fdt/syscon.h>
421.1Sjmcneill
431.1Sjmcneillstatic bool		ti_opp_probed = false;
441.1Sjmcneillstatic bool		(*ti_opp_supportedfn)(const int, const int);
451.1Sjmcneillstatic struct syscon	*ti_opp_syscon;
461.1Sjmcneill
471.2Sjmcneill#ifdef SOC_AM33XX
481.1Sjmcneill
491.1Sjmcneill#define	AM33XX_REV_OFFSET	0x0600
501.1Sjmcneill#define	AM33XX_REV_MASK		0xf0000000
511.1Sjmcneill#define	AM33XX_EFUSE_OFFSET	0x07fc
521.1Sjmcneill#define	AM33XX_EFUSE_MASK	0x00001fff
531.1Sjmcneill#define	AM33XX_EFUSE_DEFAULT	0x1e2f
541.1Sjmcneill
551.4Sthorpejstatic const struct device_compatible_entry am33xx_compat_data[] = {
561.4Sthorpej	{ .compat = "ti,am33xx" },
571.4Sthorpej	DEVICE_COMPAT_EOL
581.4Sthorpej};
591.1Sjmcneill
601.1Sjmcneillstatic bool
611.1Sjmcneillam33xx_opp_supported(const int opp_table, const int opp_node)
621.1Sjmcneill{
631.1Sjmcneill	const u_int *supported_hw;
641.1Sjmcneill	uint32_t efuse, rev;
651.1Sjmcneill	int len;
661.1Sjmcneill
671.1Sjmcneill	syscon_lock(ti_opp_syscon);
681.3Sjmcneill	rev = __BIT(__SHIFTOUT(syscon_read_4(ti_opp_syscon, AM33XX_REV_OFFSET), AM33XX_REV_MASK));
691.1Sjmcneill	efuse = __SHIFTOUT(syscon_read_4(ti_opp_syscon, AM33XX_EFUSE_OFFSET), AM33XX_EFUSE_MASK);
701.1Sjmcneill	syscon_unlock(ti_opp_syscon);
711.1Sjmcneill
721.1Sjmcneill	if (efuse == 0)
731.1Sjmcneill		efuse = AM33XX_EFUSE_DEFAULT;
741.1Sjmcneill	efuse = ~efuse;
751.1Sjmcneill
761.1Sjmcneill	supported_hw = fdtbus_get_prop(opp_node, "opp-supported-hw", &len);
771.1Sjmcneill	if (len != 8)
781.1Sjmcneill		return false;
791.1Sjmcneill
801.1Sjmcneill	if ((rev & be32toh(supported_hw[0])) == 0)
811.1Sjmcneill		return false;
821.1Sjmcneill
831.1Sjmcneill	if ((efuse & be32toh(supported_hw[1])) == 0)
841.1Sjmcneill		return false;
851.1Sjmcneill
861.1Sjmcneill	return true;
871.1Sjmcneill}
881.1Sjmcneill#endif
891.1Sjmcneill
901.1Sjmcneillstatic void
911.1Sjmcneillti_opp_probe(const int opp_table)
921.1Sjmcneill{
931.1Sjmcneill	if (ti_opp_probed)
941.1Sjmcneill		return;
951.1Sjmcneill	ti_opp_probed = true;
961.1Sjmcneill
971.1Sjmcneill	ti_opp_syscon = fdtbus_syscon_acquire(opp_table, "syscon");
981.1Sjmcneill
991.2Sjmcneill#ifdef SOC_AM33XX
1001.4Sthorpej	if (ti_opp_syscon &&
1011.4Sthorpej	    of_compatible_match(OF_finddevice("/"), am33xx_compat_data))
1021.1Sjmcneill		ti_opp_supportedfn = am33xx_opp_supported;
1031.1Sjmcneill#endif
1041.1Sjmcneill}
1051.1Sjmcneill
1061.1Sjmcneillstatic bool
1071.1Sjmcneillti_opp_supported(const int opp_table, const int opp_node)
1081.1Sjmcneill{
1091.1Sjmcneill	ti_opp_probe(opp_table);
1101.1Sjmcneill
1111.1Sjmcneill	if (!of_hasprop(opp_node, "opp-supported-hw"))
1121.1Sjmcneill		return true;
1131.1Sjmcneill
1141.1Sjmcneill	return ti_opp_supportedfn ? ti_opp_supportedfn(opp_table, opp_node) : false;
1151.1Sjmcneill}
1161.1Sjmcneill
1171.1SjmcneillFDT_OPP(ti, "operating-points-v2-ti-cpu", ti_opp_supported);
118