1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <threads.h> 6 7 #include <ddk/protocol/platform/device.h> 8 #include <ddk/protocol/platform-device-lib.h> 9 #include <ddk/protocol/serialimpl.h> 10 #include <ddk/protocol/serial.h> 11 #include <ddktl/device.h> 12 #include <ddktl/mmio.h> 13 #include <ddktl/protocol/serialimpl.h> 14 15 #include <fbl/function.h> 16 #include <fbl/mutex.h> 17 #include <lib/zx/interrupt.h> 18 #include <zircon/thread_annotations.h> 19 #include <zircon/types.h> 20 21 #include <utility> 22 23 namespace serial { 24 25 class AmlUart; 26 using DeviceType = ddk::Device<AmlUart, ddk::Unbindable>; 27 28 class AmlUart : public DeviceType, 29 public ddk::SerialImplProtocol<AmlUart, ddk::base_protocol> { 30 public: 31 // Spawns device node. 32 static zx_status_t Create(zx_device_t* parent); 33 34 // Device protocol implementation. DdkUnbind()35 void DdkUnbind() { 36 DdkRemove(); 37 } DdkRelease()38 void DdkRelease() { 39 SerialImplEnable(false); 40 delete this; 41 } 42 43 // Serial protocol implementation. 44 zx_status_t SerialImplGetInfo(serial_port_info_t* info); 45 zx_status_t SerialImplConfig(uint32_t baud_rate, uint32_t flags); 46 zx_status_t SerialImplEnable(bool enable); 47 zx_status_t SerialImplRead(void* buf, size_t length, size_t* out_actual); 48 zx_status_t SerialImplWrite(const void* buf, size_t length, size_t* out_actual); 49 zx_status_t SerialImplSetNotifyCallback(const serial_notify_t* cb); 50 51 private: 52 using Callback = fbl::Function<void(uint32_t)>; 53 AmlUart(zx_device_t * parent,const pdev_protocol_t & pdev,const serial_port_info_t & serial_port_info,ddk::MmioBuffer mmio)54 explicit AmlUart(zx_device_t* parent, const pdev_protocol_t& pdev, 55 const serial_port_info_t& serial_port_info, 56 ddk::MmioBuffer mmio) 57 : DeviceType(parent), pdev_(pdev), serial_port_info_(serial_port_info), 58 mmio_(std::move(mmio)) {} 59 60 // Reads the current state from the status register and calls notify_cb if it has changed. 61 uint32_t ReadStateAndNotify(); 62 void EnableLocked(bool enable) TA_REQ(enable_lock_); 63 int IrqThread(); 64 65 const pdev_protocol_t pdev_; 66 const serial_port_info_t serial_port_info_; 67 ddk::MmioBuffer mmio_; 68 zx::interrupt irq_; 69 70 thrd_t irq_thread_ TA_GUARDED(enable_lock_); 71 bool enabled_ TA_GUARDED(enable_lock_) = false; 72 73 Callback notify_cb_ TA_GUARDED(status_lock_) = nullptr; 74 // Last state we sent to notify_cb. 75 uint32_t state_ TA_GUARDED(status_lock_) = 0; 76 77 // Protects enabling/disabling lifecycle. 78 fbl::Mutex enable_lock_; 79 // Protects status register and notify_cb. 80 fbl::Mutex status_lock_; 81 }; 82 83 } // namespace serial 84