diff --git a/tools/patman/cmdline.py b/tools/patman/cmdline.py
index edefa778446..bee9fd21483 100644
--- a/tools/patman/cmdline.py
+++ b/tools/patman/cmdline.py
@@ -294,6 +294,7 @@ def add_series_subparser(subparsers):
 
     series_subparsers.add_parser('get-link')
     series_subparsers.add_parser('inc')
+    series_subparsers.add_parser('info')
     ls = series_subparsers.add_parser('ls', aliases=['list'])
     _add_archived(ls)
 
diff --git a/tools/patman/control.py b/tools/patman/control.py
index 3ce9736d6ba..9ba9b6e0b8e 100644
--- a/tools/patman/control.py
+++ b/tools/patman/control.py
@@ -199,6 +199,8 @@ def do_series(args, test_db=None, pwork=None, cser=None):
                                dry_run=args.dry_run, show_summary=True)
         elif args.subcmd == 'dec':
             cser.decrement(args.series, args.dry_run)
+        elif args.subcmd == 'info':
+            cser.show_info(args.series)
         elif args.subcmd == 'gather':
             cser.gather(pwork, args.series, args.version, args.show_comments,
                         args.show_cover_comments, args.gather_tags,
diff --git a/tools/patman/cseries.py b/tools/patman/cseries.py
index 1dd1550f367..e272a5839fc 100644
--- a/tools/patman/cseries.py
+++ b/tools/patman/cseries.py
@@ -861,6 +861,53 @@ class Cseries(cser_helper.CseriesHelper):
         if dry_run:
             tout.info('Dry run completed')
 
+    def show_info(self, series):
+        """Show detailed information about a series and all its versions
+
+        Args:
+            series (str): Series name, or None for current branch
+        """
+        ser, _ = self._parse_series_and_version(series, None)
+        if not ser.idnum:
+            raise ValueError(f"Series '{ser.name}' not found in database")
+
+        print(f"Series: {ser.name}")
+        print(f"  Description: {ser.desc}")
+        print(f"  Upstream: {ser.upstream or '(none)'}")
+
+        versions = self.db.ser_ver_get_for_series(ser.idnum)
+        if not isinstance(versions, list):
+            versions = [versions]
+
+        for sv in versions:
+            link_str = sv.link or '(none)'
+            print(f"\n  Version {sv.version}:")
+            print(f"    Link: {link_str}")
+            print(f"    Description: {sv.desc or '(none)'}")
+            if sv.name:
+                print(f"    Cover: {sv.name}")
+            if sv.archive_tag:
+                print(f"    Archive tag: {sv.archive_tag}")
+
+            # Show patches
+            try:
+                pclist = self.db.pcommit_get_list(sv.idnum)
+                print(f"    Patches: {len(pclist)}")
+                for pc in pclist:
+                    state = f' [{pc.state}]' if pc.state else ''
+                    print(f"      {pc.seq + 1}: {pc.subject}{state}")
+            except (ValueError, AttributeError):
+                pass
+
+            # Show notes if any
+            if sv.notes:
+                lines = sv.notes.strip().splitlines()
+                print(f"    Notes: {lines[0]}")
+                for line in lines[1:3]:
+                    print(f"           {line}")
+                if len(lines) > 3:
+                    print(f"           ... ({len(lines)} lines)")
+
     def set_upstream(self, series, ups, dry_run=False):
         """Set the upstream for a series
 
diff --git a/tools/patman/test_cseries.py b/tools/patman/test_cseries.py
index e207e8bc173..5974c69253a 100644
--- a/tools/patman/test_cseries.py
+++ b/tools/patman/test_cseries.py
@@ -4438,3 +4438,45 @@ Date:   .*
         # Future 3 weeks
         when = datetime(2025, 3, 31, 10, 0, 0)
         self.assertEqual('in 3w', wf.friendly_time(now, when))
+
+    def test_series_info(self):
+        """Test the series info command"""
+        cser = self.get_database()
+
+        # Create a series with upstream and two versions
+        cser.db.upstream_add('us', 'https://us.example.com')
+        series_id = cser.db.series_add('test-info', 'My test series', ups='us')
+        svid1 = cser.db.ser_ver_add(series_id, 1, link='12345',
+                                     desc='First version desc')
+        svid2 = cser.db.ser_ver_add(series_id, 2, desc='Second version desc')
+
+        # Add patches to v1
+        from patman.database import Pcommit
+        cser.db.pcommit_add_list(svid1, [
+            Pcommit(idnum=None, seq=0, subject='Fix the widget',
+                    svid=svid1, change_id=None, state=None,
+                    patch_id=None, num_comments=0),
+            Pcommit(idnum=None, seq=1, subject='Add widget tests',
+                    svid=svid1, change_id=None, state=None,
+                    patch_id=None, num_comments=0)])
+
+        # Add notes to v2
+        cser.db.ser_ver_set_notes(svid2, 'Fixed review feedback')
+        cser.commit()
+
+        with terminal.capture() as (out, _):
+            cser.show_info('test-info')
+
+        output = out.getvalue()
+        self.assertIn('Series: test-info', output)
+        self.assertIn('Description: My test series', output)
+        self.assertIn('Upstream: us', output)
+        self.assertIn('Version 1:', output)
+        self.assertIn('Link: 12345', output)
+        self.assertIn('First version desc', output)
+        self.assertIn('Patches: 2', output)
+        self.assertIn('Fix the widget', output)
+        self.assertIn('Add widget tests', output)
+        self.assertIn('Version 2:', output)
+        self.assertIn('Second version desc', output)
+        self.assertIn('Notes: Fixed review feedback', output)
