ingenic_rng.c revision 1.4
11.4Smacallan/*	$NetBSD: ingenic_rng.c,v 1.4 2016/02/17 20:12:42 macallan 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.4Smacallan__KERNEL_RCSID(0, "$NetBSD: ingenic_rng.c,v 1.4 2016/02/17 20:12:42 macallan 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/rndpool.h>
441.1Smacallan#include <sys/rndsource.h>
451.1Smacallan
461.1Smacallan#include <mips/ingenic/ingenic_var.h>
471.1Smacallan#include <mips/ingenic/ingenic_regs.h>
481.1Smacallan
491.1Smacallan#include "opt_ingenic.h"
501.1Smacallan
511.1Smacallanstruct ingenic_rng_softc;
521.1Smacallan
531.1Smacallanstatic int	ingenic_rng_match(device_t, cfdata_t, void *);
541.1Smacallanstatic void	ingenic_rng_attach(device_t, device_t, void *);
551.1Smacallan
561.4Smacallanstatic void	ingenic_rng_get(size_t, void *);
571.1Smacallan
581.1Smacallanstruct ingenic_rng_softc {
591.1Smacallan	device_t		sc_dev;
601.1Smacallan	bus_space_tag_t		sc_bst;
611.1Smacallan	bus_space_handle_t	sc_bsh;
621.1Smacallan
631.4Smacallan	kmutex_t		sc_lock;
641.1Smacallan	krndsource_t		sc_rndsource;
651.1Smacallan};
661.1Smacallan
671.1SmacallanCFATTACH_DECL_NEW(ingenic_rng, sizeof(struct ingenic_rng_softc),
681.1Smacallan	ingenic_rng_match, ingenic_rng_attach, NULL, NULL);
691.1Smacallan
701.1Smacallanstatic int
711.1Smacallaningenic_rng_match(device_t parent, cfdata_t cf, void *aux)
721.1Smacallan{
731.3Smacallan	const struct apbus_attach_args *aa = aux;
741.1Smacallan
751.3Smacallan	return !(strcmp(aa->aa_name, "jzrng"));
761.1Smacallan}
771.1Smacallan
781.1Smacallanstatic void
791.1Smacallaningenic_rng_attach(device_t parent, device_t self, void *aux)
801.1Smacallan{
811.1Smacallan	struct ingenic_rng_softc * const sc = device_private(self);
821.3Smacallan	const struct apbus_attach_args * const aa = aux;
831.3Smacallan	bus_addr_t addr = aa->aa_addr;
841.1Smacallan	int error;
851.1Smacallan
861.1Smacallan	sc->sc_dev = self;
871.1Smacallan	sc->sc_bst = aa->aa_bst;
881.3Smacallan	if (addr == 0)
891.3Smacallan		addr = JZ_RNG;
901.1Smacallan
911.3Smacallan	error = bus_space_map(aa->aa_bst, addr, 4, 0, &sc->sc_bsh);
921.1Smacallan	if (error) {
931.1Smacallan		aprint_error_dev(self,
941.3Smacallan		    "can't map registers for %s: %d\n", aa->aa_name, error);
951.1Smacallan		return;
961.1Smacallan	}
971.1Smacallan
981.4Smacallan	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
991.4Smacallan
1001.1Smacallan	aprint_naive(": Ingenic random number generator\n");
1011.1Smacallan	aprint_normal(": Ingenic random number generator\n");
1021.1Smacallan
1031.4Smacallan	rndsource_setcb(&sc->sc_rndsource, ingenic_rng_get, sc);
1041.1Smacallan	rnd_attach_source(&sc->sc_rndsource, device_xname(self), RND_TYPE_RNG,
1051.1Smacallan	    RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB);
1061.1Smacallan
1071.4Smacallan	ingenic_rng_get(RND_POOLBITS / NBBY, sc);
1081.1Smacallan}
1091.1Smacallan
1101.1Smacallanstatic void
1111.4Smacallaningenic_rng_get(size_t bytes_wanted, void *priv)
1121.1Smacallan{
1131.4Smacallan	struct ingenic_rng_softc * const sc = priv;
1141.1Smacallan	uint32_t data;
1151.1Smacallan
1161.4Smacallan	mutex_spin_enter(&sc->sc_lock);
1171.4Smacallan	while (bytes_wanted) {
1181.3Smacallan		data = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 0);
1191.4Smacallan		delay(1);
1201.4Smacallan		rnd_add_data_sync(&sc->sc_rndsource, &data, sizeof(data),
1211.1Smacallan		    sizeof(data) * NBBY);
1221.4Smacallan		bytes_wanted -= MIN(bytes_wanted, sizeof(data));
1231.1Smacallan	}
1241.1Smacallan	explicit_memset(&data, 0, sizeof(data));
1251.4Smacallan	mutex_spin_exit(&sc->sc_lock);
1261.1Smacallan}
127