11.7Sriastrad/*	$NetBSD: ingenic_rng.c,v 1.7 2022/03/19 11:55:03 riastradh Exp $ */
21.1Smacallan
31.1Smacallan/*-
41.1Smacallan * Copyright (c) 2015 Michael McConville
51.1Smacallan * All rights reserved.
61.1Smacallan *
71.1Smacallan * Redistribution and use in source and binary forms, with or without
81.1Smacallan * modification, are permitted provided that the following conditions
91.1Smacallan * are met:
101.1Smacallan * 1. Redistributions of source code must retain the above copyright
111.1Smacallan *    notice, this list of conditions and the following disclaimer.
121.1Smacallan * 2. Redistributions in binary form must reproduce the above copyright
131.1Smacallan *    notice, this list of conditions and the following disclaimer in the
141.1Smacallan *    documentation and/or other materials provided with the distribution.
151.1Smacallan *
161.1Smacallan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
171.1Smacallan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
181.1Smacallan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
191.1Smacallan * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
201.1Smacallan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
211.1Smacallan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
221.1Smacallan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
231.1Smacallan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
241.1Smacallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
251.1Smacallan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
261.1Smacallan * POSSIBILITY OF SUCH DAMAGE.
271.1Smacallan */
281.1Smacallan
291.1Smacallan#include <sys/cdefs.h>
301.7Sriastrad__KERNEL_RCSID(0, "$NetBSD: ingenic_rng.c,v 1.7 2022/03/19 11:55:03 riastradh Exp $");
311.2Smacallan
321.2Smacallan/*
331.2Smacallan * adapted from Jared McNeill's amlogic_rng.c
341.2Smacallan */
351.1Smacallan
361.1Smacallan#include <sys/param.h>
371.1Smacallan#include <sys/systm.h>
381.1Smacallan#include <sys/device.h>
391.1Smacallan#include <sys/mutex.h>
401.1Smacallan#include <sys/kernel.h>
411.1Smacallan#include <sys/mutex.h>
421.1Smacallan#include <sys/bus.h>
431.1Smacallan#include <sys/rndsource.h>
441.1Smacallan
451.1Smacallan#include <mips/ingenic/ingenic_var.h>
461.1Smacallan#include <mips/ingenic/ingenic_regs.h>
471.1Smacallan
481.1Smacallan#include "opt_ingenic.h"
491.1Smacallan
501.1Smacallanstruct ingenic_rng_softc;
511.1Smacallan
521.1Smacallanstatic int	ingenic_rng_match(device_t, cfdata_t, void *);
531.1Smacallanstatic void	ingenic_rng_attach(device_t, device_t, void *);
541.1Smacallan
551.4Smacallanstatic void	ingenic_rng_get(size_t, void *);
561.1Smacallan
571.1Smacallanstruct ingenic_rng_softc {
581.1Smacallan	device_t		sc_dev;
591.1Smacallan	bus_space_tag_t		sc_bst;
601.1Smacallan	bus_space_handle_t	sc_bsh;
611.1Smacallan
621.1Smacallan	krndsource_t		sc_rndsource;
631.1Smacallan};
641.1Smacallan
651.1SmacallanCFATTACH_DECL_NEW(ingenic_rng, sizeof(struct ingenic_rng_softc),
661.1Smacallan	ingenic_rng_match, ingenic_rng_attach, NULL, NULL);
671.1Smacallan
681.1Smacallanstatic int
691.1Smacallaningenic_rng_match(device_t parent, cfdata_t cf, void *aux)
701.1Smacallan{
711.3Smacallan	const struct apbus_attach_args *aa = aux;
721.1Smacallan
731.3Smacallan	return !(strcmp(aa->aa_name, "jzrng"));
741.1Smacallan}
751.1Smacallan
761.1Smacallanstatic void
771.1Smacallaningenic_rng_attach(device_t parent, device_t self, void *aux)
781.1Smacallan{
791.1Smacallan	struct ingenic_rng_softc * const sc = device_private(self);
801.3Smacallan	const struct apbus_attach_args * const aa = aux;
811.3Smacallan	bus_addr_t addr = aa->aa_addr;
821.1Smacallan	int error;
831.1Smacallan
841.1Smacallan	sc->sc_dev = self;
851.1Smacallan	sc->sc_bst = aa->aa_bst;
861.3Smacallan	if (addr == 0)
871.3Smacallan		addr = JZ_RNG;
881.1Smacallan
891.3Smacallan	error = bus_space_map(aa->aa_bst, addr, 4, 0, &sc->sc_bsh);
901.1Smacallan	if (error) {
911.1Smacallan		aprint_error_dev(self,
921.3Smacallan		    "can't map registers for %s: %d\n", aa->aa_name, error);
931.1Smacallan		return;
941.1Smacallan	}
951.1Smacallan
961.1Smacallan	aprint_naive(": Ingenic random number generator\n");
971.1Smacallan	aprint_normal(": Ingenic random number generator\n");
981.1Smacallan
991.4Smacallan	rndsource_setcb(&sc->sc_rndsource, ingenic_rng_get, sc);
1001.1Smacallan	rnd_attach_source(&sc->sc_rndsource, device_xname(self), RND_TYPE_RNG,
1011.1Smacallan	    RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB);
1021.1Smacallan}
1031.1Smacallan
1041.1Smacallanstatic void
1051.4Smacallaningenic_rng_get(size_t bytes_wanted, void *priv)
1061.1Smacallan{
1071.4Smacallan	struct ingenic_rng_softc * const sc = priv;
1081.1Smacallan	uint32_t data;
1091.1Smacallan
1101.4Smacallan	while (bytes_wanted) {
1111.3Smacallan		data = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 0);
1121.4Smacallan		delay(1);
1131.4Smacallan		rnd_add_data_sync(&sc->sc_rndsource, &data, sizeof(data),
1141.1Smacallan		    sizeof(data) * NBBY);
1151.4Smacallan		bytes_wanted -= MIN(bytes_wanted, sizeof(data));
1161.1Smacallan	}
1171.1Smacallan	explicit_memset(&data, 0, sizeof(data));
1181.1Smacallan}
119