bcm2835_rng.c revision 1.4
11.4Stls/*	$NetBSD: bcm2835_rng.c,v 1.4 2013/06/13 00:55:01 tls Exp $ */
21.1Sjmcneill
31.1Sjmcneill/*-
41.3Sskrll * Copyright (c) 2013 The NetBSD Foundation, Inc.
51.1Sjmcneill * All rights reserved.
61.1Sjmcneill *
71.1Sjmcneill * This code is derived from software contributed to The NetBSD Foundation
81.1Sjmcneill * by Jared D. McNeill
91.1Sjmcneill *
101.1Sjmcneill * Redistribution and use in source and binary forms, with or without
111.1Sjmcneill * modification, are permitted provided that the following conditions
121.1Sjmcneill * are met:
131.1Sjmcneill * 1. Redistributions of source code must retain the above copyright
141.1Sjmcneill *    notice, this list of conditions and the following disclaimer.
151.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
161.1Sjmcneill *    notice, this list of conditions and the following disclaimer in the
171.1Sjmcneill *    documentation and/or other materials provided with the distribution.
181.1Sjmcneill *
191.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201.1Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211.1Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221.1Sjmcneill * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231.1Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241.1Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251.1Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261.1Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271.1Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281.1Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291.1Sjmcneill * POSSIBILITY OF SUCH DAMAGE.
301.1Sjmcneill */
311.1Sjmcneill
321.1Sjmcneill#include <sys/cdefs.h>
331.4Stls__KERNEL_RCSID(0, "$NetBSD: bcm2835_rng.c,v 1.4 2013/06/13 00:55:01 tls Exp $");
341.1Sjmcneill
351.1Sjmcneill#include <sys/param.h>
361.1Sjmcneill#include <sys/systm.h>
371.1Sjmcneill#include <sys/device.h>
381.1Sjmcneill#include <sys/kernel.h>
391.1Sjmcneill#include <sys/bus.h>
401.1Sjmcneill#include <sys/rnd.h>
411.4Stls#include <sys/atomic.h>
421.1Sjmcneill
431.1Sjmcneill#include <arm/broadcom/bcm_amba.h>
441.1Sjmcneill#include <arm/broadcom/bcm2835reg.h>
451.1Sjmcneill#include <arm/broadcom/bcm2835_intr.h>
461.1Sjmcneill
471.1Sjmcneill#define RNG_CTRL		0x00
481.1Sjmcneill#define  RNG_CTRL_EN		__BIT(0)
491.1Sjmcneill#define RNG_STATUS		0x04
501.1Sjmcneill#define  RNG_STATUS_CNT_MASK	__BITS(31,24)
511.1Sjmcneill#define  RNG_STATUS_CNT_SHIFT	24
521.1Sjmcneill#define RNG_DATA		0x08
531.1Sjmcneill
541.1Sjmcneill#define RNG_DATA_MAX		256
551.1Sjmcneill
561.1Sjmcneillstruct bcm2835rng_softc {
571.1Sjmcneill	device_t sc_dev;
581.1Sjmcneill
591.1Sjmcneill	bus_space_tag_t sc_iot;
601.1Sjmcneill	bus_space_handle_t sc_ioh;
611.1Sjmcneill
621.1Sjmcneill	krndsource_t sc_rnd;
631.4Stls
641.4Stls	kmutex_t sc_mutex;
651.1Sjmcneill
661.1Sjmcneill	uint32_t sc_data[RNG_DATA_MAX];
671.1Sjmcneill};
681.1Sjmcneill
691.4Stlsstatic void bcmrng_get(size_t, void *);
701.1Sjmcneillstatic int bcmrng_match(device_t, cfdata_t, void *);
711.1Sjmcneillstatic void bcmrng_attach(device_t, device_t, void *);
721.1Sjmcneill
731.1SjmcneillCFATTACH_DECL_NEW(bcmrng_amba, sizeof(struct bcm2835rng_softc),
741.1Sjmcneill    bcmrng_match, bcmrng_attach, NULL, NULL);
751.1Sjmcneill
761.1Sjmcneill/* ARGSUSED */
771.1Sjmcneillstatic int
781.1Sjmcneillbcmrng_match(device_t parent, cfdata_t match, void *aux)
791.1Sjmcneill{
801.1Sjmcneill	struct amba_attach_args *aaa = aux;
811.1Sjmcneill
821.1Sjmcneill	if (strcmp(aaa->aaa_name, "bcmrng") != 0)
831.1Sjmcneill		return 0;
841.1Sjmcneill
851.1Sjmcneill	return 1;
861.1Sjmcneill}
871.1Sjmcneill
881.1Sjmcneillstatic void
891.1Sjmcneillbcmrng_attach(device_t parent, device_t self, void *aux)
901.1Sjmcneill{
911.1Sjmcneill        struct bcm2835rng_softc *sc = device_private(self);
921.1Sjmcneill 	struct amba_attach_args *aaa = aux;
931.1Sjmcneill	uint32_t ctrl;
941.1Sjmcneill
951.1Sjmcneill	aprint_naive("\n");
961.1Sjmcneill	aprint_normal(": RNG\n");
971.1Sjmcneill
981.1Sjmcneill	sc->sc_dev = self;
991.1Sjmcneill	sc->sc_iot = aaa->aaa_iot;
1001.1Sjmcneill
1011.1Sjmcneill	if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, BCM2835_RNG_SIZE, 0,
1021.1Sjmcneill	    &sc->sc_ioh)) {
1031.1Sjmcneill		aprint_error_dev(sc->sc_dev, "unable to map device\n");
1041.1Sjmcneill		return;
1051.1Sjmcneill	}
1061.1Sjmcneill
1071.4Stls	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
1081.4Stls
1091.4Stls	rndsource_setcb(&sc->sc_rnd, bcmrng_get, sc);
1101.1Sjmcneill	rnd_attach_source(&sc->sc_rnd, device_xname(self), RND_TYPE_RNG,
1111.4Stls	    RND_FLAG_NO_ESTIMATE|RND_FLAG_HASCB);
1121.1Sjmcneill
1131.2Sjmcneill	/* discard initial numbers, broadcom says they are "less random" */
1141.2Sjmcneill	bus_space_write_4(sc->sc_iot, sc->sc_ioh, RNG_STATUS, 0x40000);
1151.2Sjmcneill
1161.1Sjmcneill	/* enable rng */
1171.1Sjmcneill	ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RNG_CTRL);
1181.1Sjmcneill	ctrl |= RNG_CTRL_EN;
1191.1Sjmcneill	bus_space_write_4(sc->sc_iot, sc->sc_ioh, RNG_CTRL, ctrl);
1201.1Sjmcneill}
1211.1Sjmcneill
1221.1Sjmcneillstatic void
1231.4Stlsbcmrng_get(size_t bytes, void *priv)
1241.1Sjmcneill{
1251.4Stls        struct bcm2835rng_softc *sc = priv;
1261.1Sjmcneill	uint32_t status;
1271.4Stls	int need = bytes, cnt;
1281.1Sjmcneill
1291.4Stls        mutex_spin_enter(&sc->sc_mutex);
1301.4Stls
1311.4Stls        printf("bcmrng: asked for %d bytes", (int)bytes);
1321.4Stls
1331.4Stls	if (__predict_false(need < 1)) {
1341.4Stls		return;
1351.1Sjmcneill	}
1361.1Sjmcneill
1371.4Stls	while (need > 0) {
1381.4Stls		status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RNG_STATUS);
1391.4Stls		cnt = (status & RNG_STATUS_CNT_MASK) >> RNG_STATUS_CNT_SHIFT;
1401.4Stls		if (cnt > 0) {
1411.4Stls			bus_space_read_multi_4(sc->sc_iot, sc->sc_ioh,
1421.4Stls					       RNG_DATA, sc->sc_data, cnt);
1431.4Stls			rnd_add_data(&sc->sc_rnd, sc->sc_data,
1441.4Stls		    		     cnt * 4, cnt * 4 * NBBY);
1451.4Stls		}
1461.4Stls
1471.4Stls		need -= cnt * 4;
1481.4Stls	}
1491.4Stls	mutex_spin_exit(&sc->sc_mutex);
1501.1Sjmcneill}
151