1*482734aaSPhilipp Tomsich // SPDX-License-Identifier: GPL-2.0+ 2*482734aaSPhilipp Tomsich /* 3*482734aaSPhilipp Tomsich * (C) Copyright 2018 Theobroma Systems Design und Consulting GmbH 4*482734aaSPhilipp Tomsich */ 5*482734aaSPhilipp Tomsich 6*482734aaSPhilipp Tomsich #include <common.h> 7*482734aaSPhilipp Tomsich #include <bootcount.h> 8*482734aaSPhilipp Tomsich #include <dm.h> 9*482734aaSPhilipp Tomsich #include <rtc.h> 10*482734aaSPhilipp Tomsich 11*482734aaSPhilipp Tomsich static const u8 bootcount_magic = 0xbc; 12*482734aaSPhilipp Tomsich 13*482734aaSPhilipp Tomsich struct bootcount_rtc_priv { 14*482734aaSPhilipp Tomsich struct udevice *rtc; 15*482734aaSPhilipp Tomsich u32 offset; 16*482734aaSPhilipp Tomsich }; 17*482734aaSPhilipp Tomsich 18*482734aaSPhilipp Tomsich static int bootcount_rtc_set(struct udevice *dev, const u32 a) 19*482734aaSPhilipp Tomsich { 20*482734aaSPhilipp Tomsich struct bootcount_rtc_priv *priv = dev_get_priv(dev); 21*482734aaSPhilipp Tomsich const u16 val = bootcount_magic << 8 | (a & 0xff); 22*482734aaSPhilipp Tomsich 23*482734aaSPhilipp Tomsich if (rtc_write16(priv->rtc, priv->offset, val) < 0) { 24*482734aaSPhilipp Tomsich debug("%s: rtc_write16 failed\n", __func__); 25*482734aaSPhilipp Tomsich return -EIO; 26*482734aaSPhilipp Tomsich } 27*482734aaSPhilipp Tomsich 28*482734aaSPhilipp Tomsich return 0; 29*482734aaSPhilipp Tomsich } 30*482734aaSPhilipp Tomsich 31*482734aaSPhilipp Tomsich static int bootcount_rtc_get(struct udevice *dev, u32 *a) 32*482734aaSPhilipp Tomsich { 33*482734aaSPhilipp Tomsich struct bootcount_rtc_priv *priv = dev_get_priv(dev); 34*482734aaSPhilipp Tomsich u16 val; 35*482734aaSPhilipp Tomsich 36*482734aaSPhilipp Tomsich if (rtc_read16(priv->rtc, priv->offset, &val) < 0) { 37*482734aaSPhilipp Tomsich debug("%s: rtc_write16 failed\n", __func__); 38*482734aaSPhilipp Tomsich return -EIO; 39*482734aaSPhilipp Tomsich } 40*482734aaSPhilipp Tomsich 41*482734aaSPhilipp Tomsich if (val >> 8 == bootcount_magic) { 42*482734aaSPhilipp Tomsich *a = val & 0xff; 43*482734aaSPhilipp Tomsich return 0; 44*482734aaSPhilipp Tomsich } 45*482734aaSPhilipp Tomsich 46*482734aaSPhilipp Tomsich debug("%s: bootcount magic does not match on %04x\n", __func__, val); 47*482734aaSPhilipp Tomsich return -EIO; 48*482734aaSPhilipp Tomsich } 49*482734aaSPhilipp Tomsich 50*482734aaSPhilipp Tomsich static int bootcount_rtc_probe(struct udevice *dev) 51*482734aaSPhilipp Tomsich { 52*482734aaSPhilipp Tomsich struct ofnode_phandle_args phandle_args; 53*482734aaSPhilipp Tomsich struct bootcount_rtc_priv *priv = dev_get_priv(dev); 54*482734aaSPhilipp Tomsich struct udevice *rtc; 55*482734aaSPhilipp Tomsich 56*482734aaSPhilipp Tomsich if (dev_read_phandle_with_args(dev, "rtc", NULL, 0, 0, &phandle_args)) { 57*482734aaSPhilipp Tomsich debug("%s: rtc backing device not specified\n", dev->name); 58*482734aaSPhilipp Tomsich return -ENOENT; 59*482734aaSPhilipp Tomsich } 60*482734aaSPhilipp Tomsich 61*482734aaSPhilipp Tomsich if (uclass_get_device_by_ofnode(UCLASS_RTC, phandle_args.node, &rtc)) { 62*482734aaSPhilipp Tomsich debug("%s: could not get backing device\n", dev->name); 63*482734aaSPhilipp Tomsich return -ENODEV; 64*482734aaSPhilipp Tomsich } 65*482734aaSPhilipp Tomsich 66*482734aaSPhilipp Tomsich priv->rtc = rtc; 67*482734aaSPhilipp Tomsich priv->offset = dev_read_u32_default(dev, "offset", 0); 68*482734aaSPhilipp Tomsich 69*482734aaSPhilipp Tomsich return 0; 70*482734aaSPhilipp Tomsich } 71*482734aaSPhilipp Tomsich 72*482734aaSPhilipp Tomsich static const struct bootcount_ops bootcount_rtc_ops = { 73*482734aaSPhilipp Tomsich .get = bootcount_rtc_get, 74*482734aaSPhilipp Tomsich .set = bootcount_rtc_set, 75*482734aaSPhilipp Tomsich }; 76*482734aaSPhilipp Tomsich 77*482734aaSPhilipp Tomsich static const struct udevice_id bootcount_rtc_ids[] = { 78*482734aaSPhilipp Tomsich { .compatible = "u-boot,bootcount-rtc" }, 79*482734aaSPhilipp Tomsich { } 80*482734aaSPhilipp Tomsich }; 81*482734aaSPhilipp Tomsich 82*482734aaSPhilipp Tomsich U_BOOT_DRIVER(bootcount_rtc) = { 83*482734aaSPhilipp Tomsich .name = "bootcount-rtc", 84*482734aaSPhilipp Tomsich .id = UCLASS_BOOTCOUNT, 85*482734aaSPhilipp Tomsich .priv_auto_alloc_size = sizeof(struct bootcount_rtc_priv), 86*482734aaSPhilipp Tomsich .probe = bootcount_rtc_probe, 87*482734aaSPhilipp Tomsich .of_match = bootcount_rtc_ids, 88*482734aaSPhilipp Tomsich .ops = &bootcount_rtc_ops, 89*482734aaSPhilipp Tomsich }; 90